<轉>cocos2d-x學習筆記(五)仿真樹葉飄落效果的實現(精靈旋轉、翻轉、鐘擺運動等綜合運用)

轉載自ufolr的博客 原文鏈接:http://blog.csdn.net/ufolr/article/details/7624851ios

 

 最近項目中須要一個落葉的效果,原本想用粒子特效來實現,可是幾經調試,雖然調出了落葉的效果,可是並非十分理想,最大的不足就是落葉是平面的,沒有立體感,雖然把落葉作小以後倒是立體感的感受會有所緩解,但總不能把樹葉無限的縮小吧,並且立體感的缺失在粒子特效中確實是一個始終存在的問題。做爲一個最求品質的程序猿,最終仍是決定本身設精靈動做來實現。函數

    在分析了粒子特效實現的原理並在國內外論壇上爬了半天,最後邊實驗邊修改,終於完成了一個可行的仿真感較強的立體的落葉效果,如今就拿出來跟你們分享一下。測試

原理->樹葉飄落動做分析:this

 

         樹葉下落過程分解爲下落+擺動+葉片自傳spa

 

         也就是隻要將這三個動做實現,並同時執行就能夠實現樹葉飄落的效果。.net

 

 下面就拿出代碼具體解析實現過程:3d

 

老規矩,先上.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__

 

 接下來是具體的實現,爲了咱們能不斷的產生天然、隨和的落葉,咱們分三步來完成:blog

 

           1:第一次初始化;2:落葉動做的實現;3:下落動做完成從新設定落葉開始。rem

 

 

上代碼,先看看用到的頭文件:

 

#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值的大小爲你的精靈被擋住部分的像素值。

相關文章
相關標籤/搜索