转载自ufolr的博客 原文连接:http://www.jb51.cc/article/p-mrdyjsly-dt.html
最近项目中需要一个落叶的效果,本来想用粒子特效来实现,但是几经调试,虽然调出了落叶的效果,但是并不是十分理想,最大的不足就是落叶是平面的,没有立体感,虽然把落叶做小之后却是立体感的感觉会有所缓解,但总不能把树叶无限的缩小吧,而且立体感的缺失在粒子特效中确实是一个始终存在的问题。作为一个最求品质的程序猿,最终还是决定自己设精灵动作来实现。
在分析了粒子特效实现的原理并在国内外论坛上爬了半天,最后边实验边修改,终于完成了一个可行的仿真感较强的立体的落叶效果,现在就拿出来跟大家分享一下。
原理->树叶飘落动作分析:
树叶下落过程分解为:下落+摆动叶片自传。
也就是只要将这三个动作实现,并同时执行就可以实现树叶飘落的效果。
下面就拿出代码具体解析实现过程:
老规矩,先上.h的内容,.h就不多解释了:
#ifndef__LEAF_H__ #define__LEAF_H__ #include"cocos2d.h" USING_NS_CC; classLeaf:publiccocos2d::cclayer { public: virtualboolinit(); voIDresetLeafPos(CCNode*sender);//叶片位置重置函数 voIDplayLeafAnim(CCSprite*spriteLeaf);//下落过程实现函数 LAYER_NODE_FUNC(Leaf); }; #endif//__LEAF_H__
接下来是具体的实现,为了我们能不断的产生自然、随和的落叶,我们分三步来完成:
1:第一次初始化;2:落叶动作的实现;3:下落动作完成重新设定落叶开始。
上代码,先看看用到的头文件:
#include<iostream> #include<ctime> #include<cstdlib> #include"Leaf.h" usingnamespacestd; enum{TAG_LEAF1=101,TAG_LEAF2}; 初始化树叶精灵的设定:
<spanstyle="Font-size:12px;">@H_864_301@boolLeaf::init() CCSprite*spriteLeaf1=CCSprite::spriteWithfile("img_yezi_1.png"); spriteLeaf1->setRotation(30);//旋转角度 spriteLeaf1->setAnchorPoint(ccp(0.5,3));//设置精灵锚点 spriteLeaf1->setposition(ccp(450,500));//叶子1第一次初始位置 spriteLeaf1->setScale(0.5);//设置叶片大小 this->addChild(spriteLeaf1,100,TAG_LEAF1); this->playLeafAnim(spriteLeaf1);//调用play函数播实现叶动作 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); returntrue; }</span>
将精灵的锚点设定在其高度的3倍的位置,加上旋转动作后,叶片会产生单摆的动作效果。再加上下落的动作,就会有树叶飘落的感觉了。
<spanstyle="Font-size:12px;">//叶子飘落动作 voIDLeaf::playLeafAnim(CCSprite*spriteLeaf) { @H_864_301@intiTag=spriteLeaf->getTag(); cclog("playtag%d",iTag); ccTimetime,roTime; floatfAngle1,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((@H_864_301@UINT)GetCurrentTime()); intiRandPos=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);//设置深度抬高60,避免出现使用CCOrbitCamera实现空间翻转时产生错位和遮挡等问题 //CCDirector::sharedDirector()->setDepthTest(false); //关闭深度测试同样可以避免上述问题,不过,推荐使用深度设置setVertexZ来正确解决,因为有时你可能需要遮挡的效果,关闭深度测试后将造成遮挡效果的缺失 CCOrbitCamera*orbit=CCOrbitCamera::actionWithDuration(8,1,360,45,0); //让树叶精灵始终执行三维翻转的动作 CCRepeat*fz3d=CCRepeat::actionWithAction(orbit,-1);//无限循环执行叶片翻转的动作 //CCRepeatForever*fz3d=CCRepeatForever::actionWithAction(orbit); //由于下面使用CCSpawn同时执行动作,所以不可以使用无限次数类型的动作,而因使用有线次数循环CCRepeat将循环次数设置为-1 //用CCEaseInOut包装落叶摆动的动作,让树叶的进入、出现更自然(淡入淡出效果) CCEaseInOut*ease1=CCEaseInOut::actionWithAction(rotaBy1,3); CCEaseInOut*ease2=CCEaseInOut::actionWithAction(rotaBy2,3); //摆动动作合成 CCFiniteTimeAction*seq2=CCSequence::actions(ease1,ease2,NulL);//依次执行顺时针、逆时针摆动 CCRepeat*baIDong=CCRepeat::actionWithAction(seq2,0)">//摆动合成 //动作执行->同时执行所有动作 spriteLeaf->runAction(CCSpawn::actions(putdown,baIDong,fz3d,NulL)); }</span> 现在叶子飘落的主干就设定完毕了,其实看上去并不复杂,就是三个动作:下落+摆动+翻转,未来使落叶更自然,我们尽可能的在数据可变的范围内使用随机参数,我这里用了系统时间做种子来产生随机数,但是我感觉产生的随机数还是不够理想,如果你有更好的种子,可以告诉我。其实还有很多参数可以在限定范围内使用随机数,由于时间关系我没有逐个去调试,而是直接设定了一个固定值。有时间你可以逐个设定实验,找到最佳的数据范围。
现在为了使我们的落叶能够源源不断的产生,我们还需要让落叶的产生和消亡循环起来:
//重置叶子的位置 voIDLeaf::resetLeafPos(CCNode*sender) intiTag=@H_864_301@int(sender->getTag());//获得被重置叶片的标签 intiZoder=@H_864_301@int(sender->getZOrder());//获取被重置叶片的z轴值 sender->removeFromParentAndCleanup(true);//清除已经落到底点的叶子 charsimg[15]="img_yezi_1.png"; _snprintf(simg,sizeof(simg),"img_yezi_%d.png",iTag%100); CCPointpos; floatfAngle; //随机生成叶子的起始位置 UINT)GetCurrentTime()); intiRand=(rand()%200); if(iTag==TAG_LEAF1) pos=ccp(iRand,600); fAngle=30; 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);//重置后的树叶再次执行飘落动作
这样3d仿真的落叶的效果就基本实现了,为了节约时间,这里只写了2片叶子的情况,多片叶子的情况可以举一反三,多加几片叶子就行。这里需要注意的是在使用CCOrbitCamera来实现三维空间的翻转时,由于openGL绘图的关系,我们得将精灵的深度设置上浮,以避免openGL绘图时精灵的部分被后面的色彩遮挡。
解决遮挡问题可以直接关闭深度测试CCDirector::sharedDirector()->setDepthTest(false);
也可以设置精灵VertexZ上浮spriteLeaf->setVertexZ(60);
如果你的程序不需要深度测试,你大可以直接关了它,但是你不能确定是的程序是否每个地方都没有用到深度测试,所以,推荐设置VertexZ值来避免你的精灵被遮挡。VertexZ值的大小为你的精灵被挡住部分的像素值。
总结以上是内存溢出为你收集整理的cocos2d-x学习笔记(五)仿真树叶飘落效果的实现(精灵旋转、翻转、钟摆运动等综合运用)全部内容,希望文章能够帮你解决cocos2d-x学习笔记(五)仿真树叶飘落效果的实现(精灵旋转、翻转、钟摆运动等综合运用)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)