Cocos2d-x入門之旅[3]動作
Cocos通過動作(Action)讓精靈動起來,把數個動作組成序列(Sequence)就能讓精靈做出連續的動作,在動作中我們可以改變精靈的位置,旋轉角度,縮放比例,等等
動作(Action)
首先我們建立一個Action
物件,同樣使用create
,這裡我們還是使用HelloWorld場景裡的那張圖片
auto sprite = Sprite::create("sinnosuke.png");
在setPosition
之後我們加上一句
// 在2秒內:向右移動精靈50畫素,向上移動精靈10畫素 auto moveBy = MoveBy::create(2, Vec2(50, 10)); sprite->runAction(moveBy);
這個精靈就會平滑地根據我們輸入的引數移動
如果把moveBy
改成moveTo
,那就會是另一種結果:
// 在2秒內:把精靈移動到座標(50,10)
auto moveTo = MoveTo::create(2, Vec2(50, 10));
sprite->runAction(moveTo);
精靈直接移動到了(50,10)
(錨點在其正中間)
By 和 To 的區別
By
算的是相對於節點物件的當前位置To
算的是絕對位置,不考慮當前節點物件在哪
動作組合
你還可以把多個動作加入到一個序列(Sequence)裡,讓精靈按執行序列
auto moveBy = MoveBy::create(2, Vec2(50, 10)); auto moveTo = MoveTo::create(2, Vec2(50, 10)); auto delay = DelayTime::create(1);//設定一個一秒的延時,也加入序列中 auto seq = Sequence::create(moveBy, delay, moveTo, nullptr); //做動作moveBy後,延時1秒,做動作moveTo sprite->runAction(seq);
精靈就會按次序執行序列裡的動作
序列我們之後再詳細講解
基本動作
移動
MoveTo
,MoveBy
,使精靈在指定時間內移動到指定地點
auto sprite = Sprite::create("sinnosuke.png"); auto delay = DelayTime::create(1); // 在2秒內:向右移動精靈50畫素,向上移動精靈10畫素 auto moveBy = MoveBy::create(2, Vec2(50, 10)); // 在2秒內:把精靈移動到座標(50,10) auto moveTo = MoveTo::create(2, Vec2(50, 10)); auto seq = Sequence::create(moveBy, delay, moveTo, nullptr); sprite->runAction(seq);
效果如上圖
旋轉
RotateTo
,RotateBy
,使精靈在指定時間內旋轉到指定角度
auto sprite = Sprite::create("sinnosuke.png");
auto delay = DelayTime::create(1);
// 在2秒內:把精靈從原始位置順時針旋轉40度
auto rotateBy = RotateBy::create(2.0f, 40.0f);
// 在2秒內:把精靈從目前位置旋轉到順時針40度的位置
auto rotateTo = RotateTo::create(2.0f, 40.0f);
auto seq = Sequence::create(rotateBy, delay, rotateTo, nullptr);
sprite->runAction(seq);
你應該會看到這個圖片轉了一次就不動了,其實不是不動了
因為在第一個動作後你已經讓圖片轉到了順時針40度的位置,第二個動作的目標“把精靈從目前位置旋轉到順時針40度的位置”即為目前的位置,所以看上去就是不動了
建議你把兩個動作先後順序對調一下,執行看看,方便理解
縮放
ScaleBy
ScaleTo
在指定時間內完成指定比例縮放
auto sprite = Sprite::create("sinnosuke.png");
// Scale uniformly by 3x over 2 seconds
// 在2秒內:把精靈等比放大到3倍
auto scaleBy = ScaleBy::create(2.0f, 3.0f);
// Scale X by 5 and Y by 3x over 2 seconds
// 在2秒內:把精靈的x軸放大到3倍並把y軸放大到3倍
auto scaleBy = ScaleBy::create(2.0f, 3.0f, 3.0f);
// 在2秒內:把精靈縮放到:等比放大3倍的狀態
auto scaleTo = ScaleTo::create(2.0f, 3.0f);
// Scale X to 5 and Y to 3x over 2 seconds
// 在2秒內:把精靈縮放到:x軸放大到3倍,把y軸放大到3倍的狀態
auto scaleTo = ScaleTo::create(2.0f, 3.0f, 3.0f);
通過對旋轉的理解(主要是To和By的理解),上述程式碼不難看懂,這裡不多給出執行效果了,感興趣可以自己寫個Sequence
測試
淡入淡出
FadeIn
淡入,FadeOut
淡出 (其實就是修改節點物件的透明度屬性,FadeIn
從完全透明到完全不透明,FadeOut
相反)
auto sprite = Sprite::create("sinnosuke.png");
auto delay = DelayTime::create(1);//設定一個一秒的延時,也加入序列中
auto fadeIn = FadeIn::create(1.0f);
auto fadeOut = FadeOut::create(2.0f);
auto seq = Sequence::create(delay, fadeOut, delay, fadeIn, nullptr);
sprite->runAction(seq);
也很簡單,程式碼也給出了,可以自己執行看看
色彩混合
使用 TintTo
TintBy
,將一個實現了 NodeRGB
協議的節點物件進行色彩混合
auto sprite = Sprite::create("sinnosuke.png");
auto delay = DelayTime::create(1);
// 指定RGB值為節點著色
auto tintTo = TintTo::create(2.0f, 120.0f, 232.0f, 254.0f);
// 指定RGB值為增量為節點著色
auto tintBy = TintBy::create(2.0f, 120.0f, 232.0f, 254.0f);
auto seq = Sequence::create(tintTo, delay, tintBy, nullptr);
sprite->runAction(seq);
變化如下:
此外還有幀動畫和變速運動
幀動畫使用 Animate
物件,通過每隔一個短暫時間進行影象替代的方式,實現一個動畫效果
變速動作可以讓節點物件具有加速度,用以模仿物理運動,降低效能損耗
序列(Sequence)
顧名思義,序列就是多個動作按照特定順序的一個排列(當然也能反向執行)
其實序列就是一種封裝多個動作的物件,當這個物件執行時,被封裝的動作會順序執行
Sequence
一個 Sequence
可以包含任何數量的動作物件,回撥方法和其它序列,Cocos2d-x 允許把一個方法新增進去 CallFunc
物件,然後將 CallFunc
新增到 Sequence
,這樣,在執行序列的時候就能觸發方法呼叫
auto mySprite = Node::create();
auto moveTo1 = MoveTo::create(2, Vec2(50,10));
auto moveBy1 = MoveBy::create(2, Vec2(100,10));
auto moveTo2 = MoveTo::create(2, Vec2(150,10));
auto delay = DelayTime::create(1);
mySprite->runAction(
Sequence::create(
moveTo1,
delay,
moveBy1,
delay.clone(),
moveTo2, nullptr
)
);
Spawn
Spawn
和 Sequence
非常相似,但 Spawn
同時執行所有的動作
Spawn
物件可以新增任意數量的動作,和其它 Spawn
物件,可能不同動作的執行時間不一致,在這種情況下,他們不會同時結束
auto myNode = Node::create();
auto moveTo1 = MoveTo::create(2, Vec2(50,10));
auto moveBy1 = MoveBy::create(2, Vec2(100,10));
auto moveTo2 = MoveTo::create(2, Vec2(150,10));
myNode->runAction(Spawn::create(moveTo1, moveBy1, moveTo2, nullptr));
克隆
克隆(Clone) 的功能和字面含義一樣,如果你對一個節點物件使用了 clone()
方法,你就獲得了這個節點物件的拷貝
為什麼要使用 clone()
方法? 因為當 Action
物件執行時會產生一個內部狀態,記錄著節點屬性的改變,當你想將一個建立的動作,重複使用到不同的節點物件時,如果不用 clone()
方法,就無法確定這個動作的屬性到底是怎樣的(因為被使用過,產生了內部狀態),這會造成難以預料的結果
我們來看示例,假如你有一個座標位置是 (0,0)
的 heroSprite
,執行這樣一個動作:
MoveBy::create(10, Vec2(400,100));
你的 heroSprite
就在 10s 的時間中,從 (0,0)
移動到了 (400,100)
,heroSprite
有了一個新位置 (400,100)
,更重要的是動作物件也有了節點位置相關的內部狀態了
現在假如你有一個座標位置是 (200,200)
的 emenySprite
,你還使用這個相同的動作,emenySprite
就會移動到 (800,200)
的座標位置,並不是你想要的結果,因為第二次將這個動作應用的時候,它已經有內部狀態了
使用 clone()
能避免這種情況,克隆獲得一個新的動作物件,新的物件沒有之前的內部狀態
以下錯誤的用法:
auto heroSprite = Sprite::create("herosprite.png");
auto enemySprite = Sprite::create("enemysprite.png");
auto moveBy = MoveBy::create(10, Vec2(400,100));
heroSprite->runAction(moveBy);
enemySprite->runAction(moveBy);
使用 clone()
的正確情況:
auto heroSprite = Sprite::create("herosprite.png");
auto enemySprite = Sprite::create("enemysprite.png");
auto moveBy = MoveBy::create(10, Vec2(400,100));
heroSprite->runAction(moveBy);
enemySprite->runAction(moveBy->clone());
倒轉
倒轉(Reverse) 的功能也和字面意思一樣,呼叫 reverse()
可以讓一系列動作按相反的方向執行,reverse()
不是隻能簡單的讓一個 Action
物件反向執行,還能讓 Sequence
和 Spawn
倒轉
mySprite->runAction(mySpawn->reverse());
應用例項
auto mySprite = Sprite::create("mysprite.png");
mySprite->setPosition(50, 56);
auto moveBy = MoveBy::create(2.0f, Vec2(500,0));
auto scaleBy = ScaleBy::create(2.0f, 2.0f);
auto delay = DelayTime::create(2.0f);
auto delaySequence = Sequence::create(delay, delay->clone(), delay->clone(),
delay->clone(), nullptr);
auto sequence = Sequence::create(moveBy, delay, scaleBy, delaySequence, nullptr);
mySprite->runAction(sequence);
mySprite->runAction(sequence->reverse());