动作即Action,类如其名,它主要是用来改变Node对象的属性,Action对象是随着时间改变Node的属性。任何一个以Node为基类的对象都有可执行的动作对象。

      例如,你可以在一个时间段内将Sprite精灵从一个位置移动到另一个位置。

如下为MoveTo和MoveBy两个动作的实例:

// 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是绝对的,意思是它并不考虑到这个节点的当前状态。让我们看一个具体的例子:

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的位置。

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。

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倍

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之间)。与之相反的动作是“淡出”

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从当前值改变到用户设置值。

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_即可。如下例子:

auto mySprite = Sprite::create("mysprite.png");

// now lets animate the sprite we moved

Vector 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对象,并使其上下跳动。

// 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

序列动作的例子

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

Spawn与Sequence类似,不同的是使用Spawn时所有动作是同时执行的。你可以有很多动作对象,甚至其他Spawn对象。


spawn

Spawn的作用与运行多个连续的runAction()语句所产生的结果是相同的。然而,使用Spawn的优点在于你可以将其放到一个序列中,从而实现特定的效果。而runAction()是不可以的。将Spawn和Sequence结合使用讲会实现很多强大的功能。

举例:

// 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:

// running the above Actions with Spawn.

auto mySpawn = Spawn::createWithTwoActions(moveBy, fadeTo);

mySprite->runAction(mySpawn);

使用连贯的runAction()语句:

// running the above Actions with consecutive runAction() statements.

mySprite->runAction(moveBy);

mySprite->runAction(fadeTo);

两个产生的效果是相同的。但是,其中一个可以在Sequence中使用Spawn。如下流程图所示:


spawn_in_a_sequence

// 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()函数使动作逆序执行。然而,这并不只是简单的逆序运行,实际上还将原始的Sequence和Spawn的属性也转换为逆序。

Using the Spawn example above reversing is simple. 上面Spawn中的例子使用逆序就会很简单:

// reverse a sequence, spawn or action

mySprite->runAction(mySpawn->reverse());

大部分Action和Sequence对象都是可逆的!

使用很简单,但是让我们来验证一下是不是这样,如下:

// 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已经为你完成了这复杂的逻辑。