1. 程式人生 > >Cocos2d-x入門之旅[3]動作

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

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

序列我們之後再詳細講解

基本動作

移動

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