ufolr原创,转载请注明:
转载自ufolr的博客 原文连接:http://blog.csdn.net/ufolr/article/details/7624851
最近项目中需要一个落叶的效果,本来想用粒子特效来实现,但是几经调试,虽然调出了落叶的效果,但是并不是十分理想,最大的不足就是落叶是平面的,没有立体感,虽然把落叶做小之后却是立体感的感觉会有所缓解,但总不能把树叶无限的缩小吧,而且立体感的缺失在粒子特效中确实是一个始终存在的问题。作为一个最求品质的程序猿,最终还是决定自己设精灵动作来实现。
在分析了粒子特效实现的原理并在国内外论坛上爬了半天,最后边实验边修改,终于完成了一个可行的仿真感较强的立体的落叶效果,现在就拿出来跟大家分享一下。
原理->树叶飘落动作分析:
树叶下落过程分解为:下落+摆动+叶片自传。
也就是只要将这三个动作实现,并同时执行就可以实现树叶飘落的效果。
下面就拿出代码具体解析实现过程:
老规矩,先上.h的内容,.h就不多解释了:
- #ifndef __LEAF_H__
- #define __LEAF_H__
-
- #include "cocos2d.h"
- USING_NS_CC;
-
- class Leaf : public cocos2d::CCLayer
- {
- public:
- virtual bool init();
-
- void resetLeafPos(CCNode* sender);
- void playLeafAnim(CCSprite *spriteLeaf);
-
- LAYER_NODE_FUNC(Leaf);
- };
-
- #endif // __LEAF_H__
接下来是具体的实现,为了我们能不断的产生自然、随和的落叶,我们分三步来完成:
1:第一次初始化;2:落叶动作的实现;3:下落动作完成重新设定落叶开始。
上代码,先看看用到的头文件:
- #include <iostream>
- #include <ctime>
- #include <cstdlib>
-
- #include"Leaf.h"
-
- using namespace std;
-
- enum {TAG_LEAF1 = 101, TAG_LEAF2};
初始化树叶精灵的设定:
- <span style="font-size:12px;">bool Leaf::init()
- {
- CCSprite *spriteLeaf1 = CCSprite::spriteWithFile("img_yezi_1.png");
- spriteLeaf1->setRotation(30);
- spriteLeaf1->setAnchorPoint(ccp(0.5, 3));
- spriteLeaf1->setPosition(ccp(450, 500));
- spriteLeaf1->setScale(0.5);
-
- this->addChild(spriteLeaf1,100,TAG_LEAF1);
- this->playLeafAnim(spriteLeaf1);
-
- CCSprite *spriteLeaf2 = CCSprite::spriteWithFile("img_yezi_2.png");
- spriteLeaf2->setRotation(50);
- spriteLeaf2->setAnchorPoint(ccp(0.5, 3));
- spriteLeaf2->setPosition(ccp(200, 540));
- spriteLeaf2->setScale(0.5);
-
- this->addChild(spriteLeaf2,101,TAG_LEAF2);
- this->playLeafAnim(spriteLeaf2);
-
- return true;
- }</span>
将精灵的锚点设定在其高度的3倍的位置,加上旋转动作后,叶片会产生单摆的动作效果。再加上下落的动作,就会有树叶飘落的感觉了。
- <span style="font-size:12px;">
- void Leaf::playLeafAnim(CCSprite *spriteLeaf)
- {
- int iTag = spriteLeaf->getTag();
-
- CCLog("playtag%d", iTag);
- ccTime time, roTime;
- float fAngle1, fAngle2;
- if (iTag == TAG_LEAF1)
- {
- CCLog("tag1");
- time = 10;
- roTime = 2.5;
- fAngle1 = -80;
- fAngle2 = 80;
- }
- else
- {
- CCLog("tag2");
- time = 14;
- roTime = 3.2;
- fAngle1 = -100;
- fAngle2 = 100;
- }
- CCLog("rotime%ffAngle1%ffAngle2%f",roTime, fAngle1,fAngle1);
-
- srand((UINT)GetCurrentTime());
- int iRandPos = rand() % 250;
- CCLog("Pianyi%d", iRandPos);
-
- CCMoveTo *moveTo = CCMoveTo::actionWithDuration(time, ccp(CCDirector::sharedDirector()->getWinSize().width - iRandPos, 30));
- CCCallFuncN *actDone = CCCallFuncN::actionWithTarget(this, callfuncN_selector(Leaf::resetLeafPos));
- CCFiniteTimeAction *putdown = CCSequence::actions(moveTo, actDone, NULL);
-
- CCRotateBy *rotaBy1 = CCRotateBy::actionWithDuration(roTime, fAngle1);
- CCRotateBy *rotaBy2 = CCRotateBy::actionWithDuration(roTime, fAngle2);
-
-
- spriteLeaf->setVertexZ(60);
-
-
- CCOrbitCamera * orbit = CCOrbitCamera::actionWithDuration(8, 1, 0, 0, 360, 45, 0);
-
- CCRepeat *fz3d = CCRepeat::actionWithAction(orbit, -1);
-
-
-
-
- CCEaseInOut *ease1 = CCEaseInOut::actionWithAction(rotaBy1, 3);
- CCEaseInOut *ease2 = CCEaseInOut::actionWithAction(rotaBy2, 3);
-
- CCFiniteTimeAction *seq2 = CCSequence::actions(ease1, ease2, NULL);
- CCRepeat *baidong = CCRepeat::actionWithAction(seq2, -1);
-
-
- spriteLeaf->runAction(CCSpawn::actions(putdown, baidong, fz3d, NULL));
-
- }</span>
现在叶子飘落的主干就设定完毕了,其实看上去并不复杂,就是三个动作:下落+摆动+翻转,未来使落叶更自然,我们尽可能的在数据可变的范围内使用随机参数,我这里用了系统时间做种子来产生随机数,但是我感觉产生的随机数还是不够理想,如果你有更好的种子,可以告诉我。其实还有很多参数可以在限定范围内使用随机数,由于时间关系我没有逐个去调试,而是直接设定了一个固定值。有时间你可以逐个设定实验,找到最佳的数据范围。
现在为了使我们的落叶能够源源不断的产生,我们还需要让落叶的产生和消亡循环起来:
- <span style="font-size:12px;">
- void Leaf::resetLeafPos(CCNode* sender)
- {
- int iTag = int(sender->getTag());
- int iZoder = int(sender->getZOrder());
- sender->removeFromParentAndCleanup(true);
-
- char sImg[15] = "img_yezi_1.png";
- _snprintf(sImg, sizeof(sImg), "img_yezi_%d.png", iTag % 100);
-
- CCPoint pos;
- float fAngle;
-
- srand((UINT)GetCurrentTime());
- int iRand = (rand() % 200);
- if (iTag == TAG_LEAF1)
- {
- pos = ccp(iRand, 600);
- fAngle = 30;
- }
- else
- {
- pos = ccp(iRand, 570);
- fAngle = 50;
- }
-
- CCSprite *spriteLeaf = CCSprite::spriteWithFile(sImg);
- spriteLeaf->setScale(0.5);
- spriteLeaf->setAnchorPoint(ccp(0.5, 3));
- spriteLeaf->setRotation(fAngle);
- spriteLeaf->setPosition(pos);
-
- this->addChild(spriteLeaf, iZoder,iTag);
- this->playLeafAnim(spriteLeaf);
- }</span>
这样3d仿真的落叶的效果就基本实现了,为了节约时间,这里只写了2片叶子的情况,多片叶子的情况可以举一反三,多加几片叶子就行。这里需要注意的是在使用CCOrbitCamera来实现三维空间的翻转时,由于openGL绘图的关系,我们得将精灵的深度设置上浮,以避免openGL绘图时精灵的部分被后面的色彩遮挡。
解决遮挡问题可以直接关闭深度测试CCDirector::sharedDirector()->setDepthTest(false);
也可以设置精灵VertexZ上浮spriteLeaf->setVertexZ(60);
如果你的程序不需要深度测试,你大可以直接关了它,但是你不能确定是的程序是否每个地方都没有用到深度测试,所以,推荐设置VertexZ值来避免你的精灵被遮挡。VertexZ值的大小为你的精灵被挡住部分的像素值。
转自:http://blog.csdn.net/ufolr/article/details/7624851