cocos2dx[3.x](11)——拖尾漸隱效果MotionStreak

【嘮叨】

    在遊戲的實現過程中,我們有時會需要在某個遊戲對象上的運動軌跡上實現拖尾漸隱效果,這種感覺就好像是類似飛機拉線似的拖尾巴,使我們的遊戲在視覺上感覺很好。

    比如:刀光、子 彈的運動軌跡、流星劃痕等等。

    cocos2d-x提供了一種內置的拖尾漸隱效果的實現方法:MotionStreak

    偷了幾張圖,呵呵呵呵呵。。。

wKioL1TPq8jAfIB8AADmwIntX14300.jpg

 

wKiom1TPquXSRxlLAApmPU4wty0372.gif

 

    當然要做出酷炫的拖尾效果,都是需要與 粒子特效Particle 相結合的。

    如下再附一張唯美的拖尾效果(MotionStreak + 粒子特效),增加大家學習的激情。

    雖然我不會弄愛心,但是我覺得你學完 MotionStreak,你肯定就會弄下面的愛心了。。。

wKioL1TPrE3CDGN0AAIdutCiloU678.gif

 

【致謝】

    http://blog.csdn.net/honghaier/article/details/8600896 (源碼原理深入分析)

    http://cn.cocos2d-x.org/tutorial/show?id=2225 (《水果忍者》划動刀光實現)

    http://blog.csdn.net/dionysos_lai/article/details/39083031 (流星拖尾效果實現)

 


 

【MotionStreak】

 

1、原理

    MotionStreak 的拖尾效果,原理實際上是:在相應距離內動態生成一段段的條帶,然後一段段逐漸的消隱。

    可以指定消隱的速度fade(時間秒),一段條帶最小距離minSeg,以及條帶的寬度粗細(stroke),條帶的顏色值(color),以及相應的紋理圖片對象。

    原理說明:MotionStreak在移動的過程中(setPosition位置發生改變時),會動態生成一段段條帶段,然後這些條帶段會在生命週期fade秒內,漸漸隱去(慢慢變透明),從而形成了拖尾的效果。

    如下如所示:

wKioL1TQQMjSzflQAACKwye5gVk442.jpg

    PS:因爲是一段段條帶相連形成拖尾,所以如果條帶太粗(stroke太大),在視覺上可能會出現“脫節”的效果,就像上面的圖一樣。所以在實際使用中,stroke的大小設置應該合理。

 

2、創建方式

    創建MotionStreak有兩種方式:

        > 一種是用圖片資源文件作爲紋理創建。

        > 另一種是通過紋理圖片Texture2D創建。

    各個參數的說明,在“原理”中已經給出解釋。

/** 
 *	創建MotionStreak 的兩種方式
 **/
	// fade         : 拖尾漸隱時間(秒)
	// minSeg       : 最小的片段長度(漸隱片段的大小)。拖尾條帶相連頂點間的最小距離。
	// stroke       : 漸隱條帶的寬度。
	// color        : 片段顏色值。
	// path         : 紋理圖片的文件名。
	// texture      : 紋理圖片的對象指針。
	static MotionStreak* create(float fade, float minSeg, float stroke, const Color3B& color, const std::string& path);

	static MotionStreak* create(float fade, float minSeg, float stroke, const Color3B& color, Texture2D* texture);


	// 使用舉例
	auto motionstreak = MotionStreak::create(1.0f, 1.0f, 10.0f, Color3B(255, 0, 0), "streak.png");
//

 

3、相關函數

    爲了實現拖尾漸隱效果,MotionStreak還對Node類的一些函數進行了重載,如update、draw、setPosition等。

    每當MotionStreak改變了位置(setPosition)後,就會形成一條拖尾。而update裏則根據位置信息產生一段段新的頂點(條帶段),並讓之前生成的條帶段漸隱或消失。

//
/**
 *	相關函數
 *	tintWithColor                   : 設置頂點顏色值。
 *	reset                           : 刪除所有條帶段,重置。
 *	setFastMode                     : 設置快速模式。
 *	setStartingPositionInitialized  : 不需要了解,也不需要去使用。
 **/
	// 條帶段使用的顏色值
	void tintWithColor(const Color3B& colors);

	// 重置,刪除所有條帶段
	void reset();

	// 設置是否是快速模式, 默認爲true
	// 當爲快速模式時,新的頂點被更快的加入,但是新的頂點具有更小的精確值
	// PS:實踐測試,請寬恕若菜的無知,若菜實在看不出有何區別。。。
	inline bool isFastMode() const { return _fastMode; }
	inline void setFastMode(bool bFastMode) { _fastMode = bFastMode; }

	// 在剛創建MotionStreak的時候會置爲false(表示創建後,還未移動過)
	// 一旦改變Position(即移動後),會置爲true(表示拖尾效果開始了,然後移動就會有拖尾的效果了)
	// PS:一般不會手動去設置它,所以不需要了解這個函數。
	inline bool isStartingPositionInitialized() const { return _startingPositionInitialized; }
	inline void setStartingPositionInitialized(bool bStartingPositionInitialized) { _startingPositionInitialized = bStartingPositionInitialized; }
//

 

4、支持Action動作

    MotionStreak繼承自Node類。而既然它一旦移動(位置Position發生改變)就會拉出一條拖尾,那麼執行 MoveTo/MoveBy 或者 JumpTo/JumpBy 等等Action動作,自然也是可以形成拖尾效果的啦。

 

5、使用步驟

    (1)創建MotionStreak。MotionStreak::create()。

    (2)將MotionStreak加入到場景中。this->addChild()。

    (3)設置位置MotionStreak->setPosition();或執行移動Action動作。

    (4)一旦改變了位置之後,就會形成一段拖尾效果了。

 


 

【代碼實踐】

 

1、《水果忍者》划動刀光效果(MotionStreak + 粒子特效)

    代碼實現可參見:http://cn.cocos2d-x.org/tutorial/show?id=2225

    手勢划動產生的刀光效果,是利用觸摸移動事件,改變MotionStreak的位置,來形成拖尾的。

wKiom1TPquXSRxlLAApmPU4wty0372.gif    

 

2、《流星劃痕效果》(精靈移動 + MotionStreak + 粒子效果)

    代碼實現可參見:http://blog.csdn.net/dionysos_lai/article/details/39083031

    流星的尾巴,是在schedule/update中不斷改變MotionStreak的位置,來形成拖尾的。

wKioL1TQTWPBwjVpAAGiNb26GBE810.jpg

 

以下,再讓我介紹一個MotionStreak的簡單實現的“酷炫”例子吧。

 

3、通過觸摸事件,實現拖尾效果

    圖片資源偷自《流星劃痕效果》。

wKioL1TQUUahL20lAAAErR9tYA8286.jpg  [PIC_XX.png]

wKiom1TQUF7jFOcfAAANAcgpGjo545.jpg  [steak.png]

 

    預期實現效果:

        > 觸摸開始touchBegan,流星的位置設置爲觸摸點位置。

        > 觸摸移動touchMoved,流星跟隨觸摸點移動而移動,同時MotionStreak跟隨流星移動,形成拖尾效果。

 

    創建兩種不同規格的MotionStreak,看看效果。

        > 設置minSeg = 50、stroke = 30、color = WHITE、紋理爲steak.png 

        > 設置minSeg = 1  、stroke = 10、color = RED    、紋理爲steak.png 

 

 3.1、在HelloWorld.h中添加如下變量與函數。

//
class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();
    virtual bool init();
    CREATE_FUNC(HelloWorld);

    // 觸摸事件 回調函數
    bool onTouchBegan(Touch* pTouch, Event* pEvent);
    void onTouchMoved(Touch* pTouch, Event* pEvent);
    
private:
    Sprite* star;         // 流星精靈
    MotionStreak* streak; // 拖尾
};
//

 

 3.2、在HelloWorld.cpp的init()中,創建流星精靈、MotionStreak拖尾,並添加觸摸監聽事件。

//
bool HelloWorld::init()
{
    if ( !Layer::init() ) return false;
    
    
    // 流星精靈Sprtie
    star = Sprite::create("PIC_XX.png");
    star->setPosition(100, 100);
    this->addChild(star);
    
    
    // 流星拖尾MotionStreak
    streak = MotionStreak::create(0.5f, 50, 30, Color3B::WHITE, "steak.png");
//    streak = MotionStreak::create(0.5f, 1, 10, Color3B::RED, "steak.png");
    streak->setPosition(star->getPosition()); // 設置拖尾streak的位置
    this->addChild(streak);
    
    
    // 註冊單點觸摸
    auto dispatcher = this->getEventDispatcher();
    auto listener = EventListenerTouchOneByOne::create();
    listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this); // 觸摸開始
    listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this); // 觸摸移動
    dispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    
    return true;
}
//

 

 3.3、實現觸摸事件

            > 觸摸開始touchBegan  :流星位置設置爲觸摸點。

            > 觸摸移動touchMoved :流星移動,streak跟隨流星移動,形成拖尾效果。

//
// 觸摸開始 :設置star和streak的位置
bool HelloWorld::onTouchBegan(Touch* pTouch, Event* pEvent)
{
    // 獲取觸摸點位置
    Vec2 pos = pTouch->getLocation();
    
    // 設置位置
    star->setPosition(pos);
    streak->setPosition(star->getPosition());
    
    // 刪除所有活動條帶段
    streak->reset();
    
    return true;
}


// 觸摸移動 :移動star和streak的位置
void HelloWorld::onTouchMoved(Touch* pTouch, Event* pEvent)
{
    // 觸摸移動的偏移量
    Vec2 delta = pTouch->getDelta();
    
    // 設置位置
    star->setPosition(star->getPosition() + delta);
    streak->setPosition(star->getPosition());
}
//

 

 3.4、運行結果

    (1)設置minSeg = 50、stroke = 30、color = WHITE、紋理爲steak.png 。

wKiom1TQXbShRTGdABEGdg6odoE316.gif

 

    (2)設置minSeg = 1  、stroke = 10、color = RED    、紋理爲steak.png 。

wKiom1TQXbjDADbpAAn8suFheik669.gif

 

    (3)關於streak->reset() 函數。

        細心的小夥伴,肯定發現了我在上面的兩個GIF圖片的一開始,鼠標到處點了好幾下。

        爲什麼我會做這種“無用”操作呢?因爲接下來我要講的就是我爲什麼亂點的原因。i_f07.gif

        我在 onTouchBegan 中寫了這麼一句話:streak->reset() 。

        如果去掉這句話。那麼每次觸摸開始時,流星直接移動到觸摸點,streak也跟隨改變位置,就會出現如下的現象:沒有觸摸拖動,只是點擊鼠標,也會出現拖尾劃痕。

        而 streak->reset() 的作用就是:清除所有活動條帶段。

wKioL1TQXqWT3_dqAAc8Ryqn9hM065.gif

 

 3.5、分析與總結

        > 如果minSeq和stroke設置較大,即每一段條帶都比較長或寬,視覺上就會看到明顯“一節一節”的那種效果。

        > 如果拖尾效果不與粒子特效組合使用的話,就會像上面的例子那樣,比較單調。

        > MotionStreak只要改變位置,就會形成拖尾效果。無論是setPosition,還是執行動作(MoveTo、JumpTo)。

        > reset() 函數可以清除當前所有存在的漸隱條帶,即所謂的重置。

 

    我只能講到這裏了,MotionStreak能發揮多大的作用,就看大家怎麼用了。

    希望大家都能組合成各種“酷炫”的拖尾效果。i_f32.gif

 

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