1. 程式人生 > >cocos2dx 3.2 學習篇之六(精靈運動,自定義運動軌跡(太極八卦))

cocos2dx 3.2 學習篇之六(精靈運動,自定義運動軌跡(太極八卦))

        好了,今天想要講的是如何讓精靈按照自己定義的路徑去運動,官方給我們了一個action類,裡面有很多運動的型別,比如bezier曲線運動,比如jump運動等等,設計好了運動之後,我們只要讓精靈調運runAction()即可。 本人呢是十足的秦時明月粉絲,特別喜歡裡面 的 少司命!!!簡直是我的女神呀,所以自然想和少司命搭上一點關係那,就記得當初少司命 搭救 盜跖 那次 耍了一招 用樹葉畫八卦陣放大招技能來著。 然後就讓我各種各種激動(原諒我愛少司命愛的那麼深沉!)

      好的,轉入正題,首先我們可以看看利用 粒子系統運動軌跡做出來效果如何。。。

這個是我靜態的粒子系統,是樹葉繞著中心轉,有一點點散開的效果:


這個是粒子系統在在八卦路線的時候樣子,如果有少司命的纖細小手的話技能就好看了:


由於本人用了粒子系統有散開效果,所有早先的路徑下葉子就有點散開了,也可以通過葉子濃度看出葉子經過的路徑方向。

       首先我們來分析原理,最一開始,我們畫了一個 半徑為R,中心點為(a,b)的圓,等圓畫完以後緊接著畫一個半斤為 R/2 ,中心點為(a-R/2 , b)的半個圓(上半個圓弧),再接著,我們就畫半徑為 R/2 ,中心點為 (a+R/2 , b )的半圓弧(在圖中由於截圖過早的問題還沒有畫完整)。這樣,我們要的八卦效果就出來了。。。

       由上面分析可知,我們必須要解決畫圓演算法:由初中還是高中知識可知,x^2 + y^2 = R^2。然後再做適當平移(a,b)就可以得到我們指定中心點為(a,b),半徑為R的圓了。 當然 x^2 + y^2 = R^2 求解由於正負的關係考慮比較複雜 ,所以我把它轉化成為 : (R*cos(α))^2 + (R*sin(α))^2  = R^2

所以我們的圓上點座標為 (a+R*cos(α) ,a+R*sin(α) ), 其中 α > 0 && α <2 * Pi , 這樣就是我們要畫的正圓了。通過 對 α 範圍控制,我們也可以畫我們指定想要的半圓。

//定義一個結構體,包含裡中心點座標以及要畫圓的半徑長度
typedef struct _WuzhuangConfig
{
    cocos2d::Point centerPosition;//中心點座標
    float rudius;//半徑
}WuzhuangConfig;
//根據畫圓進度t以及圓的配置資訊計算出圓上點座標
static inline Vec2 PointAt(float t /*這裡的t代表畫圓進度,若單純順時針畫一個圓時,與動作進度相同
                                    ,若逆時針或者畫半圓等需要一定對映關係*/
                           , const WuzhuangConfig c )
{
    float x = - c.rudius * cos(3.1415926 * t * 2  ) + c.centerPosition.x ;
    //上面加負號時因為從左手邊開始畫起
    float y = c.rudius * sin(3.1415926 * t * 2  ) + c.centerPosition.y;
    return Vec2(x,y);
}

       好,上面解決了畫圓問題,下面我們來剖析我們畫圓的順序與 動作進度 t (0代表動作起點,1代表動作結束,0.5代表動作執行到了剛剛好一半) 之間關係 。 

       上面大圓的周長是全路徑的 2/3 (初中知識不解釋),小半圓分別佔了全路徑的 1/6 。

       故 t < 2.0/3 && t>0 時 , 我們執行畫大圓操作。因為我們要畫的整個大圓 ,而不是2/3個圓,故我們需要把動作進度對映到畫圓進度上 即畫大圓的進度 p = t * 3/2 。這樣就可以畫出整個大圓了。

       同理 t < 5/6 && t >2/3 時,p = (t- 2.0/3) * 3  ; 當 t >5/6 && t < 1 時,p = 7.0/2 - t * 3 ;

    知道了這個對映關係以後,我們就可以寫出整個畫八卦的根據 動作進度 t 的函式

void Wuzhuang::update(float t)
{
    if(_target)
    {
       if(t < 2.0/3)
       {
           _target->setPosition(PointAt( 3.0 / 2 * t, m_config ));
       }
       else
        {
            if(t < 5.0/6)
            {
                _target->setPosition(PointAt((t- 2.0/3) * 3 , m_config1/*小圓1配置資訊*/ ));
            }
            else
            {
                _target->setPosition(PointAt( 7.0/2 - t * 3, m_config2/*小圓2配置資訊*/ ));
            }
        }
    }
}

介紹完了畫圓核心的,剩下的就是簡單設定配置屬性和定義一個呼叫介面了。
//小圓的配置資訊
WuzhuangConfig m_config1,m_config2;
//初始化
bool Wuzhuang::initWithDuration(float t, const WuzhuangConfig& c)
{
    if (ActionInterval::initWithDuration(t))
    {
        m_config = c;
        
        m_config1.rudius = c.rudius/2;
        m_config2.rudius = c.rudius/2;
        
        m_config1.centerPosition = c.centerPosition - Vec2(c.rudius/2,0);
        m_config2.centerPosition = c.centerPosition + Vec2(c.rudius/2,0);
        return true;
    }
    return false;
}

//外部呼叫的靜態介面
Wuzhuang* Wuzhuang::actionWithDuration(float t,const WuzhuangConfig& c)
{
    Wuzhuang* pWuzhuang = new Wuzhuang();
    pWuzhuang ->initWithDuration(t, c);
    pWuzhuang ->autorelease();
    return pWuzhuang;
}

基本整個程式碼就是這樣了。。這樣外部就可以呼叫了。呼叫的話就像呼叫bezierby一樣呼叫就好了。
    WuzhuangConfig m_config;
    m_config.centerPosition = Vec2(370, 500);
    m_config.rudius = 200;
    
    Wuzhuang* pAction = Wuzhuang::actionWithDuration(4, m_config);
    p->runAction(pAction);


     所有想要自定義的動作都可以通過這樣實現。如果不懂可以去看看BezierBy這樣的類他們時怎麼實現的,仿照他們這樣寫就可以了。。。