zoukankan      html  css  js  c++  java
  • <转>cocos2d-x学习笔记(五)仿真树叶飘落效果的实现(精灵旋转、翻转、钟摆运动等综合运用)

    转载自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));//叶子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);
    
    	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);//设置深度抬高60,避免出现使用CCOrbitCamera实现空间翻转时产生错位和遮挡等问题
    	//CCDirector::sharedDirector()->setDepthTest(false);
    	//关闭深度测试同样可以避免上述问题,不过,推荐使用深度设置setVertexZ来正确解决,因为有时你可能需要遮挡的效果,关闭深度测试后将造成遮挡效果的缺失
    	CCOrbitCamera * orbit = CCOrbitCamera::actionWithDuration(8, 1, 0, 0, 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, -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());//获取被重置叶片的z轴值
    	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值的大小为你的精灵被挡住部分的像素值。

     

     

     

  • 相关阅读:
    Best Time to Buy and Sell Stock
    Remove Nth Node From End of List
    Unique Paths
    Swap Nodes in Pairs
    Convert Sorted Array to Binary Search Tree
    Populating Next Right Pointers in Each Node
    Maximum Subarray
    Climbing Stairs
    Unique Binary Search Trees
    Remove Duplicates from Sorted Array
  • 原文地址:https://www.cnblogs.com/bucengyongyou/p/3242197.html
Copyright © 2011-2022 走看看