仿真树叶飘落效果的实现(精灵旋转、翻转、钟摆运动等综合运用)

来源:互联网 发布:淘宝合约机预售啥意思 编辑:程序博客网 时间:2024/04/29 00:39

转载自ufolr的博客 原文连接:http://blog.csdn.net/ufolr/article/details/7624851


          最近项目中需要一个落叶的效果,本来想用粒子特效来实现,但是几经调试,虽然调出了落叶的效果,但是并不是十分理想,最大的不足就是落叶是平面的,没有立体感,虽然把落叶做小之后却是立体感的感觉会有所缓解,但总不能把树叶无限的缩小吧,而且立体感的缺失在粒子特效中确实是一个始终存在的问题。作为一个最求品质的程序猿,最终还是决定自己设精灵动作来实现。



         在分析了粒子特效实现的原理并在国内外论坛上爬了半天,最后边实验边修改,终于完成了一个可行的仿真感较强的立体的落叶效果,现在就拿出来跟大家分享一下。


原理->树叶飘落动作分析:

         树叶下落过程分解为下落+摆动+叶片自传

         也就是只要将这三个动作实现,并同时执行就可以实现树叶飘落的效果。



下面就拿出代码具体解析实现过程:


老规矩,先上.h的内容,.h就不多解释了:

[cpp] view plaincopyprint?
  1. #ifndef __LEAF_H__  
  2. #define __LEAF_H__  
  3.   
  4. #include "cocos2d.h"  
  5. USING_NS_CC;  
  6.   
  7. class Leaf : public cocos2d::CCLayer  
  8. {  
  9. public:  
  10.     virtual bool init();  
  11.   
  12.     void resetLeafPos(CCNode* sender);//叶片位置重置函数  
  13.     void playLeafAnim(CCSprite *spriteLeaf);//下落过程实现函数  
  14.   
  15.     LAYER_NODE_FUNC(Leaf);  
  16. };  
  17.   
  18. #endif // __LEAF_H__  

        接下来是具体的实现,为了我们能不断的产生自然、随和的落叶,我们分三步来完成:


           1:第一次初始化;2:落叶动作的实现;3:下落动作完成重新设定落叶开始。



上代码,先看看用到的头文件:

[cpp] view plaincopyprint?
  1. #include <iostream>  
  2. #include <ctime>  
  3. #include <cstdlib>  
  4.   
  5. #include"Leaf.h"  
  6.   
  7. using namespace std;  
  8.   
  9. enum {TAG_LEAF1 = 101, TAG_LEAF2};  

初始化树叶精灵的设定:

[cpp] view plaincopyprint?
  1. <span style="font-size:12px;">bool Leaf::init()  
  2. {  
  3.     CCSprite *spriteLeaf1 = CCSprite::spriteWithFile("img_yezi_1.png");  
  4.     spriteLeaf1->setRotation(30);//旋转角度  
  5.     spriteLeaf1->setAnchorPoint(ccp(0.5, 3));//设置精灵锚点  
  6.     spriteLeaf1->setPosition(ccp(450, 500));//叶子1第一次初始位置  
  7.     spriteLeaf1->setScale(0.5);//设置叶片大小  
  8.   
  9.     this->addChild(spriteLeaf1,100,TAG_LEAF1);  
  10.     this->playLeafAnim(spriteLeaf1);//调用play函数播实现叶动作  
  11.        
  12.     CCSprite *spriteLeaf2 = CCSprite::spriteWithFile("img_yezi_2.png");  
  13.     spriteLeaf2->setRotation(50);  
  14.     spriteLeaf2->setAnchorPoint(ccp(0.5, 3));  
  15.     spriteLeaf2->setPosition(ccp(200, 540));  
  16.     spriteLeaf2->setScale(0.5);  
  17.   
  18.     this->addChild(spriteLeaf2,101,TAG_LEAF2);  
  19.     this->playLeafAnim(spriteLeaf2);  
  20.   
  21.     return true;  
  22. }</span>  

          将精灵的锚点设定在其高度的3倍的位置,加上旋转动作后,叶片会产生单摆的动作效果。再加上下落的动作,就会有树叶飘落的感觉了。

[cpp] view plaincopyprint?
  1. <span style="font-size:12px;">//叶子飘落动作  
  2. void Leaf::playLeafAnim(CCSprite *spriteLeaf)  
  3. {  
  4.     int iTag = spriteLeaf->getTag();  
  5.        
  6.     CCLog("playtag%d", iTag);  
  7.     ccTime time, roTime;  
  8.     float fAngle1, fAngle2;  
  9.     if (iTag == TAG_LEAF1)  
  10.     {  
  11.         CCLog("tag1");  
  12.         time = 10;//叶子下落的时间  
  13.         roTime = 2.5;//叶子单向摆动一次时间  
  14.         fAngle1 = -80;//叶子逆时针摆动角度  
  15.         fAngle2 = 80;//顺时针摆动角度  
  16.     }  
  17.     else  
  18.     {  
  19.         CCLog("tag2");  
  20.         time = 14;  
  21.         roTime = 3.2;  
  22.         fAngle1 = -100;  
  23.         fAngle2 = 100;  
  24.     }  
  25.     CCLog("rotime%ffAngle1%ffAngle2%f",roTime, fAngle1,fAngle1);  
  26.     //随机生成叶子横向偏移值  
  27.     srand((UINT)GetCurrentTime());  
  28.     int iRandPos = rand() % 250;  
  29.     CCLog("Pianyi%d", iRandPos);  
  30.     //叶子所运动到的位置  
  31.     CCMoveTo *moveTo = CCMoveTo::actionWithDuration(time, ccp(CCDirector::sharedDirector()->getWinSize().width - iRandPos, 30));  
  32.     CCCallFuncN *actDone = CCCallFuncN::actionWithTarget(this, callfuncN_selector(Leaf::resetLeafPos));  
  33.     CCFiniteTimeAction *putdown = CCSequence::actions(moveTo, actDone, NULL);  
  34.     //叶子旋转动作  
  35.     CCRotateBy *rotaBy1 = CCRotateBy::actionWithDuration(roTime, fAngle1);  
  36.     CCRotateBy *rotaBy2 = CCRotateBy::actionWithDuration(roTime, fAngle2);  
  37.   
  38.     //叶子翻转动作  
  39.     spriteLeaf->setVertexZ(60);//设置深度抬高60,避免出现使用CCOrbitCamera实现空间翻转时产生错位和遮挡等问题  
  40.     //CCDirector::sharedDirector()->setDepthTest(false);  
  41.     //关闭深度测试同样可以避免上述问题,不过,推荐使用深度设置setVertexZ来正确解决,因为有时你可能需要遮挡的效果,关闭深度测试后将造成遮挡效果的缺失  
  42.     CCOrbitCamera * orbit = CCOrbitCamera::actionWithDuration(8, 1, 0, 0, 360, 45, 0);  
  43.     //让树叶精灵始终执行三维翻转的动作  
  44.     CCRepeat *fz3d = CCRepeat::actionWithAction(orbit, -1);//无限循环执行叶片翻转的动作  
  45.     //CCRepeatForever *fz3d = CCRepeatForever::actionWithAction(orbit);  
  46.     //由于下面使用CCSpawn同时执行动作,所以不可以使用无限次数类型的动作,而因使用有线次数循环CCRepeat将循环次数设置为-1  
  47.       
  48.     //用CCEaseInOut包装落叶摆动的动作,让树叶的进入、出现更自然(淡入淡出效果)  
  49.     CCEaseInOut *ease1 = CCEaseInOut::actionWithAction(rotaBy1, 3);  
  50.     CCEaseInOut *ease2 = CCEaseInOut::actionWithAction(rotaBy2, 3);  
  51.     //摆动动作合成  
  52.     CCFiniteTimeAction *seq2 = CCSequence::actions(ease1, ease2, NULL);//依次执行顺时针、逆时针摆动  
  53.     CCRepeat *baidong = CCRepeat::actionWithAction(seq2, -1);//摆动合成  
  54.   
  55.     //动作执行->同时执行所有动作  
  56.     spriteLeaf->runAction(CCSpawn::actions(putdown, baidong, fz3d, NULL));  
  57.       
  58. }</span>  
         现在叶子飘落的主干就设定完毕了,其实看上去并不复杂,就是三个动作:下落+摆动+翻转,未来使落叶更自然,我们尽可能的在数据可变的范围内使用随机参数,我这里用了系统时间做种子来产生随机数,但是我感觉产生的随机数还是不够理想,如果你有更好的种子,可以告诉我。其实还有很多参数可以在限定范围内使用随机数,由于时间关系我没有逐个去调试,而是直接设定了一个固定值。有时间你可以逐个设定实验,找到最佳的数据范围。

         现在为了使我们的落叶能够源源不断的产生,我们还需要让落叶的产生和消亡循环起来:

[cpp] view plaincopyprint?
  1. <span style="font-size:12px;">//重置叶子的位置  
  2. void Leaf::resetLeafPos(CCNode* sender)  
  3. {  
  4.     int iTag = int(sender->getTag());//获得被重置叶片的标签  
  5.     int iZoder = int(sender->getZOrder());//获取被重置叶片的z轴值  
  6.     sender->removeFromParentAndCleanup(true);//清除已经落到底点的叶子  
  7.        
  8.     char sImg[15] = "img_yezi_1.png";  
  9.     _snprintf(sImg, sizeof(sImg), "img_yezi_%d.png", iTag % 100);  
  10.   
  11.     CCPoint pos;  
  12.     float fAngle;  
  13.     //随机生成叶子的起始位置  
  14.     srand((UINT)GetCurrentTime());  
  15.     int iRand = (rand() % 200);  
  16.     if (iTag == TAG_LEAF1)  
  17.     {  
  18.         pos = ccp(iRand, 600);  
  19.         fAngle = 30;  
  20.     }  
  21.     else  
  22.     {  
  23.         pos = ccp(iRand, 570);  
  24.         fAngle = 50;  
  25.     }  
  26.     //重新生成新的叶片,在起点处释放  
  27.     CCSprite *spriteLeaf = CCSprite::spriteWithFile(sImg);  
  28.     spriteLeaf->setScale(0.5);  
  29.     spriteLeaf->setAnchorPoint(ccp(0.5, 3));  
  30.     spriteLeaf->setRotation(fAngle);  
  31.     spriteLeaf->setPosition(pos);  
  32.   
  33.     this->addChild(spriteLeaf, iZoder,iTag);  
  34.     this->playLeafAnim(spriteLeaf);//重置后的树叶再次执行飘落动作  
  35. }</span>  

          这样3d仿真的落叶的效果就基本实现了,为了节约时间,这里只写了2片叶子的情况,多片叶子的情况可以举一反三,多加几片叶子就行。这里需要注意的是在使用CCOrbitCamera来实现三维空间的翻转时,由于openGL绘图的关系,我们得将精灵的深度设置上浮,以避免openGL绘图时精灵的部分被后面的色彩遮挡。

         解决遮挡问题可以直接关闭深度测试CCDirector::sharedDirector()->setDepthTest(false);

         也可以设置精灵VertexZ上浮spriteLeaf->setVertexZ(60);

         如果你的程序不需要深度测试,你大可以直接关了它,但是你不能确定是的程序是否每个地方都没有用到深度测试,所以,推荐设置VertexZ值来避免你的精灵被遮挡。VertexZ值的大小为你的精灵被挡住部分的像素值。


原创粉丝点击