cocos2d-x 讓精靈按照自己設定的運動軌跡行動


轉自: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,他就會沿着我們設定的橢圓運動了。當然,只要你給出你自己的運動函數軌跡,精靈就會按照你自己設定的軌跡運動。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM