Cocos2d-x入門之旅[3]動作

  • 2019 年 10 月 19 日
  • 筆記

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);

精靈就會按次序執行序列里的動作

序列我們之後再詳細講解

基本動作

移動

MoveToMoveBy,使精靈在指定時間內移動到指定地點

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);

效果如上圖

旋轉

RotateToRotateBy,使精靈在指定時間內旋轉到指定角度

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

SpawnSequence 非常相似,但 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 對象反向執行,還能讓 SequenceSpawn 倒轉

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());