2016年5月6日 星期五

0506 cocos2d-x action 範例


【Cocos2d-x 3.x】 動作類Action學習

 William的咖啡店 2015-11-25  Cocos2d-x   132原文鏈接
遊戲設計中,動作是不可缺少的,Cocos2d-x中所有的動作都繼承自Action類,而Action類繼承自Ref和Clonable類,整個動作類繼承體系如圖:

FiniteTimeAction是所有瞬時動作和延時動作的父類,Follow跟隨一個節點的動作,Speed改變一個動作的時間。,其中FiniteTimeAction的兩個子類以及這兩個子類的子類是重點。

瞬時性動作類

<ActionInstant.h>中的類是瞬時動作類,它的子類有:
//... 顯示一個節點 setVisible(true)
class Show : public ActionInstant {

};

//... 隱藏一個節點 setVisible(false)
class Hide : public ActionInstant {

};

//... 切換節點的可視屬性 setVisible(!_target->isVisible())
class ToggleVisibility : public ActionInstant {
};

//... 移除自己
class RemoveSelf : public ActionInstant {

};

// 水平翻轉精靈
class FlipX : public ActionInstant {

};

// 垂直翻轉精靈
class FlipY : public ActionInstant {

};

// 將節點放置到某個位置 
class Place : public ActionInstant {

};

// 設置動作的回調函數為 std::function<void()>
class CallFunc : public ActionInstant {
public :
    static CallFunc * create(const std::function<void()>& func);
};

// 設置動作的回調函數為 std::function<void(Node*)>
class CallFuncN : public CallFunc {
public :
    static CallFuncN * create(const std::function<void(Node*)>& func);
};


延時性動作類

<ActionInterval.h>中的類是瞬時動作類,它的子類有:

// 創建序列動畫
class Sequence : public ActionInterval {
public :
    // 這種方式創建序列動畫最後需要加nullptr
    // 比如: Sequence::create(action1, action2, nullptr);
    static Sequence* create(FiniteTimeAction *action1, ...);

    // 根據一個動作vector來創建
    static Sequence* create(const Vector<FiniteTimeAction*>& arrayOfActions);
  
    // 創建兩個動作
    static Sequence* createWithTwoActions(FiniteTimeAction *actionOne, FiniteTimeAction *actionTwo);

    // 根據變長動作數組創建序列動作
    static Sequence* createWithVariableList(FiniteTimeAction *action1, va_list args);
};

// 重複一個動作(一次)
class Repeat : public ActionInterval {
public :
    // 創建一個FiniteTimeAction動作
    static Repeat* create(FiniteTimeAction *action, unsigned int times);
};

// 創建不斷重複的動作
class RepeatForever : public ActionInterval {
public :
    // 由一個延時動作ActionInterval而創建
    static RepeatForever* create(ActionInterval *action);
};

// 創建同時執行的動作
class Spawn : public ActionInterval {
public :
    // 同序列式動作, 最後需要添加nullptr
    static Spawn* create(FiniteTimeAction *action1, ...);

    static Spawn* createWithVariableList(FiniteTimeAction *action1, va_list args);

    static Spawn* create(const Vector<FiniteTimeAction*>& arrayOfActions);

    static Spawn* createWithTwoActions(FiniteTimeAction *action1, FiniteTimeAction *action2);
};

// 旋轉動作  旋轉到某個角度
class RotateTo : public ActionInterval {

};

// 旋轉動作 旋轉一定角度
class CC_DLL RotateBy : public ActionInterval {

};

// 移動一定距離
class MoveBy : public ActionInterval {

};

// 移動到某個點
class MoveTo : public MoveBy {

};

/*---------- 這個動作By版本繼承自To版本 ----------*/
// 使某個傾斜到某個角度 
class SkewTo : public ActionInterval {

};

// 傾斜一定角度
class SkewBy : public SkewTo {

};

// 跳躍一定距離
class JumpBy : public ActionInterval {

};

// 跳躍到某個點
class JumpTo : public JumpBy {

};

// 貝塞爾曲線
class BezierBy : public ActionInterval {

};

// 
class BezierTo : public BezierBy {

};

// 縮放
class ScaleTo : public ActionInterval {

};

class ScaleBy : public ScaleTo {

};

// 閃爍
class Blink : public ActionInterval {

};

// 設置透明度
class FadeTo : public ActionInterval

// 淡入
class FadeIn : public FadeTo {

};

// 淡出
class FadeOut : public FadeTo {

};

// 延時動作
class DelayTime : public ActionInterval {

};

// 動畫
class Animate : public ActionInterval {

};

在所有延時動作裡:
  • SkewBy繼承自SkewTo, ScaleBy繼承自ScaleTo
  • RotateBy和RotateTo分別繼承自ActionInterval
    TinkTo和TinkBy分別繼承自ActionInterval
  • BesizerTo繼承自BezierBy
    MoveTo繼承自MoveBy 
    JumpTo繼承自JumpBy

動作管理

所有的動作執行都由動作管理類ActionManager對象_actionManager來管理動作,該對象定時刷新自己的update函數,然後調用每個動作的step函數,這些step再根據自身的update或結束動作。

ACTIONS

version: Cocos2d-x v3.x
update: 於 超過 1 年 前更新
Action objects are just like they sound, make a Node perform a change to its properties. Actionobjects allow the transform of Node properties in time. Any object with a base class of Node can have Action objects performed on it. As an example, you can move a Sprite from one position to another and do it over a time span.
Example of MoveTo and MoveBy action:
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 and To, what is the difference?
You will notice that each Action has a By and To version. Why? They are different in what they accomplish. A By is relative to the current state of the Node. A To action is absolute, meaning it doesn't take into account the current state of the Node. Let's take a look at a specific example:
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);

Basic Actions and how to run them

Basic actions are usually a singular action, thus accomplishing a single objective. Let's take a look at a few examples:

Move

Move the Node position over a set period of time.
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);

Rotate

Rotates a Node clockwise over 2 seconds.
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);

Scale

Scales a Node by 10 over 2 seconds.
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);

Fade In/Out

Fades In a Node.
It modifies the opacity from 0 to 255. The "reverse" of this action is FadeOut
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);

Tint

Tints a Node that implements the NodeRGB protocol from current tint to a custom one.
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);

Animate

With Animate it is possible to do simple flipbook animation with your Sprite objects. This is simply replacing the display frame at set intervals for the duration of the animation. Let's consider this example:
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));
It's hard to show an animation in text, so please run the example "Programmer Guide Sample" code to see this in action!

Easing

Easing is animating with a specified acceleration to make the animations smooth. A few things to keep in mind is that regardless of speed, ease actions always
start and finish at the same time. Ease actions are a good way to fake physics in your game! Perhaps you want a few simulated physics effects but dont want the
overhead and complexity of adding it all for a few very basic actions. Another good example is to animate menus and buttons.
Here are common easing functions displayed over a graph:
Cocos2d-x supports most of the easing function in the above graph. They are also simple to implement. Lets look at a specific use case. Lets drop a Sprite object
from the top of the screen and make it bounce.
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));
Run the example "Programmer Guide Sample" code to see this in action!

Sequences and how to run them

Sequences are a series of Action objects to be executed sequentially. This can be any number ofAction objects, Functions and even another Sequence. Functions? Yes! Cocos2d-x has aCallFunc object that allows you to create a function() and pass it in to be run in your Sequence. This allows you to add your own functionality to your Sequence objects besides just the stockAction objects that Cocos2d-x provides. This is what a Sequence looks like when executing:

An example 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);
So what is this Sequence action do?
It will executes the following actions sequentially:
Jump -> callbackJump -> Rotate -> callbackRotate
Run the example "Programmer Guide Sample" code to see this in action!

Spawn

Spawn is very similar to Sequence, except that all actions will run at the same time. You can have any number of Action objects and even other Spawn objects!
Spawn produces the same result as running multiple consecutive runAction() statements. However, the benefit of spawn is that you can put it in a Sequence
to help achieve specific effects that you cannot otherwise. Combining Spawn and Sequence is a very powerful feature
Example, given:
1
2
3
4
5
// create 2 actions and run a Spawn on a Sprite
auto mySprite = Sprite::create("mysprite.png");

auto moveBy = MoveBy::create(10, Vec2(400,100));
auto fadeTo = FadeTo::create(2.0f, 120.0f);
Using a Spawn:
1
2
3
// running the above Actions with Spawn.
auto mySpawn = Spawn::createWithTwoActions(moveBy, fadeTo);
mySprite->runAction(mySpawn);
and consecutive runAction() statements:
1
2
3
// running the above Actions with consecutive runAction() statements.
mySprite->runAction(moveBy);
mySprite->runAction(fadeTo);
Both would produce the same result. However, one can use Spawn in a Sequence. This flowchart shows the how this might look:
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);
Run the example "Programmer Guide Sample" code to see this in action!

Reverse

Reverse is exactly like it sounds. If you run a series of actions, you can call reverse() to run it in the opposite order. Backwards. However it is not just
simply running in reverse. It is actually manipulating the properties of the original Sequence orSpawn in reverse too.
Using the Spawn example above reversing is simple.
1
2
 // reverse a sequence, spawn or action
mySprite->runAction(mySpawn->reverse());
Most Action and Sequence objects are reversible!
It's easy to use, but let's make sure we see what is happening. Given:
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());
What is really happening? If we lay out the steps as a list it might be helpful:
  1. mySprite is created
  2. mySprite position is set to (50, 56)
  3. sequence starts to run
  4. sequence moves mySprite by 500, over 2 seconds, mySprite new position (550, 56)
  5. sequence delays for 2 seconds
  6. sequence scales mySprite by 2x over 2 seconds
  7. sequence delays for 6 more seconds (notice we run another sequence to accomplish this)
  8. we run a reverse on the sequence so we re-run each action backwards
  9. sequence is delayed for 6 seconds
  10. sequence scales mySprite by -2x over 2 seconds
  11. sequence delays for 2 seconds
  12. sequence moves mySprite by -500, over 2 seconds, mySprite new position (50, 56)
You can see that a reverse() is simply for you to use, but not so simple in it's internal logic. Cocos2d-x does all the heavy lifting!
i4.png (37.5 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
spawn_in_a_sequence.png (25.2 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
i5.png (30.9 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
spawn.png (17.9 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
i6.png (34.8 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
i7.png (27.6 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
easing-functions.png (66.6 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
i0.png (32.3 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
i1.png (20 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
i2.png (32.2 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
sequence.png (13.2 KB) walzer@cocos2d-x.org, 2014-12-03 05:40
i3.png (32.6 KB) walzer@cocos2d-x.org, 2014-12-03 05:40

沒有留言:

張貼留言

cocos2dx-lua 建立滑鼠監聽

重要關鍵字  EVENT_MOUSE_SCROLL addEventListenerWithSceneGraphPriority      if IsPc() then --建立滑鼠監聽         local listener = cc.EventListenerMouse...