cocos2d-x中的動作細說

Action類如其名,它可以改變Node對象的屬性,Action對象是隨着時間改變Node的屬性。任何一個以Node爲基類的對象都有可執行的動作對象。例如,你可以在一個時間段內將Sprite精靈從一個位置移動到另一個位置。

如下爲MoveToMoveBy兩個動作的實例:

1
2
3
4
5
6
7
// Move sprite to position 50,10 in 2 seconds.
auto moveTo = MoveTo::create(2, Vec2(50, 10));
mySprite1->runAction(moveTo);
 
// Move sprite 20 points to right in 2 seconds
auto moveBy = MoveBy::create(2, Vec2(20,0));
mySprite2->runAction(moveTo);

By和To的區別

或許你已經注意到了每個動作都有By和To兩個狀態。爲什麼呢?因爲它們所執行的結果是不同的。By相當於這個節點是相對的。To是絕對的,意思是它並不考慮到這個節點的當前狀態。讓我們看一個具體的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
auto mySprite = Sprite::create("mysprite.png");
mySprite->setPosition(Vec2(200, 256));
 
// MoveBy - lets move the sprite by 500 on the x axis over 2 seconds
// MoveBy is relative - since x = 200 + 200 move = x is now 400 after the move
auto moveBy = MoveBy::create(2, Vec2(500, mySprite->getPositionY()));
 
// MoveTo - lets move the new sprite to 300 x 256 over 2 seconds
// MoveTo is absolute - The sprite gets moved to 300 x 256 regardless of
// where it is located now.
auto moveTo = MoveTo::create(2, Vec2(300, mySprite->getPositionY()));
 
auto seq = Sequence::create(moveBy, delay, moveTo, nullptr);
 
mySprite->runAction(seq);

i0

基本動作以及如何執行動作

基本動作通常是一個單一的動作,只完成一個目標。讓我們看看幾個例子:

移動(Move)

在規定的時間內移動Node的位置。

1
2
3
4
5
6
7
8
9
10
11
auto mySprite = Sprite::create("mysprite.png");
 
// Move a sprite to a specific location over 2 seconds.
auto moveTo = MoveTo::create(2, Vec2(50, 0));
 
mySprite->runAction(moveTo);
 
// Move a sprite 50 pixels to the right, and 0 pixels to the top over 2 seconds.
auto moveBy = MoveBy::create(2, Vec2(50, 0));
 
mySprite->runAction(moveBy);

i1

旋轉(Rotate)

在2秒內順時針旋轉Node

1
2
3
4
5
6
7
8
9
auto mySprite = Sprite::create("mysprite.png");
 
// Rotates a Node to the specific angle over 2 seconds
auto rotateTo = RotateTo::create(2.0f, 40.0f);
mySprite->runAction(rotateTo);
 
// Rotates a Node clockwise by 40 degree over 2 seconds
auto rotateBy = RotateBy::create(2.0f, 40.0f);
mySprite->runAction(rotateBy);

i3

縮放(Scale)

在兩秒內將Node放大10倍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
auto mySprite = Sprite::create("mysprite.png");
 
// Scale uniformly by 3x over 2 seconds
auto scaleBy = ScaleBy::create(2.0f, 3.0f);
mySprite->runAction(scaleBy);
 
// Scale X by 5 and Y by 3x over 2 seconds
auto scaleBy = ScaleBy::create(2.0f, 3.0f, 3.0f);
mySprite->runAction(scaleBy);
 
// Scale to uniformly to 3x over 2 seconds
auto scaleTo = ScaleTo::create(2.0f, 3.0f);
mySprite->runAction(scaleTo);
 
// Scale X to 5 and Y to 3x over 2 seconds
auto scaleTo = ScaleTo::create(2.0f, 3.0f, 3.0f);
mySprite->runAction(scaleTo);

i4

淡入淡出

Node淡入

FadeIn修改透明度的值(0~255之間)。與之相反的動作是“淡出”

1
2
3
4
5
6
7
8
9
auto mySprite = Sprite::create("mysprite.png");
 
// fades in the sprite in 1 seconds
auto fadeIn = FadeIn::create(1.0f);
mySprite->runAction(fadeIn);
 
// fades out the sprite in 2 seconds
auto fadeOut = FadeOut::create(2.0f);
mySprite->runAction(fadeOut);

i2

色調(Tint)

Tint使節點的NodeRGB從當前值改變到用戶設置值。

1
2
3
4
5
6
7
8
9
auto mySprite = Sprite::create("mysprite.png");
 
// Tints a node to the specified RGB values
auto tintTo = TintTo::create(2.0f, 120.0f, 232.0f, 254.0f);
mySprite->runAction(tintTo);
 
// Tints a node BY the delta of the specified RGB values.
auto tintBy = TintBy::create(2.0f, 120.0f, 232.0f, 254.0f);
mySprite->runAction(tintBy);

i5

動畫(Animate)

通過Animate可以很容易地實現精靈的幀動畫效果。只要簡單的每隔一段時間替換_display frame_即可。如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
auto mySprite = Sprite::create("mysprite.png");
 
// now lets animate the sprite we moved
 
Vector<SpriteFrame*> animFrames;
animFrames.reserve(12);
animFrames.pushBack(SpriteFrame::create("Blue_Front1.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Front2.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Front3.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Left1.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Left2.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Left3.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Back1.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Back2.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Back3.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Right1.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Right2.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Right3.png", Rect(0,0,65,81)));
 
// create the animation out of the frames
Animation* animation = Animation::createWithSpriteFrames(animFrames, 0.1f);
Animate* animate = Animate::create(animation);
 
// run it and repeat it forever
mySprite->runAction(RepeatForever::create(animate));

很難以文字形式描述一個動畫,所以請運行《開發者指南示例》中動作部分的代碼查看動作效果。

減速(Easing)

Easing用一個給定的加速度來使動畫更加順暢。需要記住的是,無論速度快慢,ease動作總是同時開始和結束。在遊戲中如果你想模擬一些物理特效,但又不想過度且麻煩地使用多個非常基本的動作,那麼此時Ease動作將是模擬物理特效的一個很好的方法。這裏有另一個給菜單和按鈕添加動畫的很好的例子。

下圖顯示了一些常用的減速功能:

easing-functions

Cocos2d-x支持上圖中所顯示的大部分減速功能。這些功能也是容易實現的。讓我們一起看看一個特殊的用例。屏幕的上方添加一個Sprite對象,並使其上下跳動。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// create a sprite
auto mySprite = Sprite::create("mysprite.png");
 
// create a MoveBy Action to where we want the sprite to drop from.
auto move = MoveBy::create(2, Vec2(200, dirs->getVisibleSize().height - newSprite2->getContentSize().height));
auto move_back = move->reverse();
 
// create a BounceIn Ease Action
auto move_ease_in = EaseBounceIn::create(move->clone() );
 
// create a delay that is run in between sequence events
auto delay = DelayTime::create(0.25f);
 
// create the sequence of actions, in the order we want to run them
auto seq1 = Sequence::create(move_ease_in, delay, move_ease_in_back,
    delay->clone(), nullptr);
 
// run the sequence and repeat forever.
mySprite->runAction(RepeatForever::create(seq1));

運行“開發者指南示例”中的這部分的代碼可以查看動作效果。

序列動作以及如何執行它

Sequence可以使一系列的動作對象按順序執行。這一系列對象可以是任何數量的動作對象、函數,甚至是另外一個序列動作。函數?是的!Cocos2d-x中有一個CallFunc對象,它允許你創建一個function()函數並可以傳遞到Sequence中執行。這就允許你在序列動作對象中添加自己的函數功能,而不是僅僅侷限於Cocos2d-x中提供的動作對象。如下例爲序列動作被執行時的狀態:

sequence

序列動作的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
auto mySprite = Sprite::create("mysprite.png");
 
// create a few actions.
auto jump = JumpBy::create(0.5, Vec2(0, 0), 100, 1);
 
auto rotate = RotateTo::create(2.0f, 10);
 
// create a few callbacks
auto callbackJump = CallFunc::create([](){
log("Jumped!");
});
 
auto callbackRotate = CallFunc::create([](){
log("Rotated!");
});
 
// create a sequence with the actions and callbacks
auto seq = Sequence::create(jump, callbackJump, rotate, callbackRotate, nullptr);
 
// run it
mySprite->runAction(seq);

那麼,Sequence對象做了什麼呢?

它可以按順序執行如下動作:

Jump -> callbackJump -> Rotate -> callbackRotate

運行“開發者指南示例”中的代碼查看動作效果。

Spawn

SpawnSequence類似,不同的是使用Spawn時所有動作是同時執行的。你可以有很多動作對象,甚至其他Spawn對象。

spawn

Spawn的作用與運行多個連續的runAction()語句所產生的結果是相同的。然而,使用Spawn的優點在於你可以將其放到一個序列中,從而實現特定的效果。而runAction()是不可以的。將SpawnSequence結合使用講會實現很多強大的功能。

舉例:

1
2
3
4
// create 2 actions and run a Spawn on a Sprite
auto mySprite = Sprite::create("mysprite.png");
 
auto moveBy = MoveBy::create(10, Vec2(400,100));

使用Spawn:

1
2
3
// running the above Actions with Spawn.
auto mySpawn = Spawn::createWithTwoActions(moveBy, fadeTo);
mySprite->runAction(mySpawn);

使用連貫的runAction()語句:

1
2
3
// running the above Actions with consecutive runAction() statements.
mySprite->runAction(moveBy);
mySprite->runAction(fadeTo);

兩個產生的效果是相同的。但是,其中一個可以在Sequence中使用Spawn。如下流程圖所示:

spawn_in_a_sequence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// create a Sprite
auto mySprite = Sprite::create("mysprite.png");
 
// create a few Actions
auto moveBy = MoveBy::create(10, Vec2(400,100));
auto fadeTo = FadeTo::create(2.0f, 120.0f);
auto scaleBy = ScaleBy::create(2.0f, 3.0f);
 
// create a Spawn to use
auto mySpawn = Spawn::createWithTwoActions(scaleBy, fadeTo);
 
// tie everything together in a sequence
auto seq = Sequence::create(moveBy, mySpawn, moveBy, nullptr);
 
// run it
mySprite->runAction(seq);

運行“開發者指南示例”中的代碼查看動作效果。

Reverse(逆序)

Reverse的作用完全像它的名字一樣,例如運行一系列動作時,你完全可以調用reserve()函數使動作逆序執行。然而,這並不只是簡單的逆序運行,實際上還將原始的SequenceSpawn的屬性也轉換爲逆序。

Using the Spawn example above reversing is simple. 上面Spawn中的例子使用逆序就會很簡單:

1
2
// reverse a sequence, spawn or action
mySprite->runAction(mySpawn->reverse());

大部分ActionSequence對象都是可逆的!

使用很簡單,但是讓我們來驗證一下是不是這樣,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// create a Sprite
auto mySprite = Sprite::create("mysprite.png");
mySprite->setPosition(50, 56);
 
// create a few Actions
auto moveBy = MoveBy::create(2.0f, Vec2(500,0));
auto scaleBy = ScaleBy::create(2.0f, 2.0f);
auto delay = DelayTime::create(2.0f);
 
// create a sequence
auto delaySequence = Sequence::create(delay, delay->clone(), delay->clone(),
delay->clone(), nullptr);
 
auto sequence = Sequence::create(moveBy, delay, scaleBy, delaySequence, nullptr);
 
// run it
newSprite2->runAction(sequence);
 
// reverse it
newSprite2->runAction(sequence->reverse());

發生了什麼呢?如下步驟清單或許對我們有幫助:

  • 創建mySprite
  • 設置mySprite位置爲(50,56)
  • 開始運行sequence
  • 在兩秒內sequence將mySprite移動了500個像素,mysprite新位置爲(550,56)
  • sequence延遲2秒
  • 在兩秒內sequence將mySprite擴大兩倍
  • 延遲了6秒多(注意,這裏我們運行了另外一個sequence來完成這個)
  • 在sequence上運行一reverse,因此我們可以向後重新運行每個動作。
  • sequence被延遲了6秒
  • 在2秒內sequence將mySprite擴大了兩倍
  • sequence延遲了兩秒
  • 在兩秒內,sequence移動mySprite了-500個像素,mySprite的新位置爲(50,56)

你可以看到reverse()用起來很簡單,但是其實邏輯上並不簡單。Cocos2d-x已經爲你完成了這複雜的邏輯


轉自cocos引擎中文官網

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