cocos2d-x學習筆記(三)讓精靈按照自己設定的運動軌跡行動(曲線移動)。(以橢圓軌跡爲例)。

ufolr原創,轉載請註明:

轉載自ufolr的博客 原文連接:http://blog.csdn.net/ufolr/article/details/7447773


        在cocos2d中,系統提供了CCMove、CCJump、CCBezier(貝塞爾曲線)等讓精靈移動的action,但是有時候,爲了讓程序看上不不是那麼的呆板,或者爲了實現某些特定的功能,我們需要讓精靈按照我們自己設定的路徑(曲線運動)來移動。這就是這位篇文章我們需要討論的話題。

        自己開始也很糾結cocos2dx沒有提供更多的action動作,比如說我們要做個拋物線什麼的,雖然可以用貝塞爾曲線來模擬。

用貝塞爾曲線扔個飛鏢什麼的倒是還不錯,但當你需要重複執行action時,問題就出來了,再第二次重複貝塞爾曲線動作到時候,精靈就會飛到別的地方去了。(出現這個問題的原因,猜測貝塞爾曲線是沒有起點和終點了,在第一次執行了動作之後,之前的曲線動作並沒有被釋放,第二次再延續這個動作,就會延爲執行的那段曲線移動,當然,只是猜測,未深入研究。後來覺得不是這個原因,但具體原因未明。

        如果我們要做一個橢圓的軌跡,有人說用3~4條貝塞爾曲線來模擬,但實驗證明,在兩條貝塞爾曲線的銜接點Action會有停頓,所以效果簡直可以用魯迅先生的“目不忍視”來形容。

        於是,我們考慮自己定義曲線的路徑,讓精靈按照我們自己的定義來行動。

需求:

        將自己設定的路徑封裝成一個action,讓精靈執行,這裏以橢圓軌跡爲例。

 先來兩張效果圖:

實現:

        單獨建一個自己的動作模塊:LRActionInterval。{LRActionInterval.h&LRActionInterval.cpp

        基於cocos2d-x的CCActionInterval來封裝自己的動作,所以:

LRActionInterval.h

#include "CCActionInterval.h"//包含系統延時類動作頭文件

using namespace cocos2d;

        想一想確定一個橢圓的條件,初中老師告訴我們,確定一個橢圓我們需要知道他的空間位置(中心點座標)、長半軸(a)、和短半軸(b)(或者知道半焦距(c))。也就是我們需要三個量來確定一個橢圓,所以在LRActionInterval.h中定義一個包含三個成員的結構來作爲我們生成橢圓的參數:

// 定義一個結構來包含確定橢圓的參數
typedef struct _lrTuoyuanConfig {
	//中心點座標
	CCPoint centerPosition;
	//橢圓a長,三角斜邊
	float aLength;
	//橢圓c長,三角底邊
	float cLength;
} lrTuoyuanConfig;

        然後定義我們的橢圓的類:

class  __declspec(dllexport) LRTuoyuanBy : public CCActionInterval
{
public:
	//用“動作持續時間”和“橢圓控制參數”初始化動作
	bool initWithDuration(ccTime t, const lrTuoyuanConfig& c);
	virtual void update(ccTime time);//利用update函數來不斷的設定座標
public:
	//用“動作持續時間”和“橢圓控制參數”創建動作
	static LRTuoyuanBy *actionWithDuration(ccTime t, const lrTuoyuanConfig& c);

protected:
	lrTuoyuanConfig m_sConfig;
	CCPoint m_startPosition;
	CCPoint s_startPosition;
};
接下來是我們的實現部分:

LRActionInterval.cpp

        其實設定路徑就是不斷的刷新,將路徑上的點賦給執行action的對象。

因此,既然我們要做一個橢圓的軌跡,我們就需要得到橢圓上每個點的座標值,然後將其賦給執行action的對象。獲得橢圓的軌跡,再次回想初中老師的教導——橢圓標準方程:x^2/a+y^2/b=1。

        但這是個2次方程,利用這個方程求x、y的值的時候會需要開方,而開方後還需要確定正負,雖然可以實現功能,但是給自己增加了不少代碼量,也會浪費不少筆芯。所以我們要找一個更簡單的公式——橢圓參數方程。

        參數方程:x=acos(θ)y=bsin(θ);利用這個一次方程可以直觀的計算出當前座標點。

        由橢圓的參數方程我們可以分別寫出返回X/Y座標值的函數:

static inline float tuoyuanXat( float a, float bx, float c, ccTime t )//返回X座標
{
	//參數方程
	return -a*cos(2*3.1415926*t)+a;
}
static inline float tuoyuanYat( float a, float by, float c, ccTime t )//返回Y座標
{
	float b = sqrt(powf(a, 2) - powf(c, 2));//因爲之前定義的參數是焦距c而不是短半軸b,所以需要計算出b
	//參數方程
	return b*sin(2*3.1415926*t);
}

然後實現根據中心左邊、a、c確定橢圓:

//
//TuoyuanBy
//
LRTuoyuanBy* LRTuoyuanBy::actionWithDuration(ccTime t, const lrTuoyuanConfig& c)//利用之前定義的橢圓的三個參數初始化橢圓
{
	LRTuoyuanBy *pTuoyuanBy = new LRTuoyuanBy();
	pTuoyuanBy->initWithDuration(t, c);
	pTuoyuanBy->autorelease();

	return pTuoyuanBy;
}

bool LRTuoyuanBy::initWithDuration(ccTime t, const lrTuoyuanConfig& c)
{
	if (CCActionInterval::initWithDuration(t))
	{
                m_sConfig = c;
		return true;
	}

	return false;
}
void LRTuoyuanBy::update(ccTime time)
{
	if (m_pTarget)
	{
		CCPoint s_startPosition =m_sConfig.centerPosition;//中心點座標
		float a = m_sConfig.aLength;
		float bx = m_sConfig.centerPosition.x;
		float by = m_sConfig.centerPosition.y;
		float c = m_sConfig.cLength;
		float x = tuoyuanXat(a, bx, c, time);//調用之前的座標計算函數來計算出座標值
		float y = tuoyuanYat(a, by, c, time);
		m_pTarget->setPosition(ccpAdd(s_startPosition, ccp(x-a, y)));//由於我們畫計算出的橢圓你做值是以原點爲中心的,所以需要加上我們設定的中心點座標
	}
}

        這樣我們只需要在程序中像使用CCBezier一樣使用LRTuoyuan,讓精靈執行這個Action,他就會沿着我們設定的橢圓運動了。當然,只要你給出你自己的運動函數軌跡,精靈就會按照你自己設定的軌跡運動。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章