Cocos2d-x 开发者指南04:动作

2015年03月20日 11:26 0 点赞 0 评论 更新于 2025-11-21 17:49

动作概述

动作即 Action,其主要用途是改变 Node 对象的属性。Action 对象会随着时间的推移改变 Node 的属性,任何以 Node 为基类的对象都能够执行动作。

例如,我们可以在一个时间段内将 Sprite 精灵从一个位置移动到另一个位置。以下是 MoveToMoveBy 两个动作的实例:

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

By 和 To 的区别

每个动作通常都有 ByTo 两个状态,这是因为它们执行的结果不同。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 + 500 move = x is now 700 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);

基本动作以及如何执行动作

基本动作通常是单一的动作,仅完成一个目标。下面介绍几种常见的基本动作:

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

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

缩放(Scale)

在两秒内对 Node 进行缩放操作。

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, 5.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, 5.0f, 3.0f);
mySprite->runAction(scaleTo);

淡入淡出

FadeIn 用于修改透明度的值(范围在 0 - 255 之间),实现淡入效果,与之相反的动作是 FadeOut(淡出)。

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)

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

动画(Animate)

通过 Animate 可以轻松实现精灵的帧动画效果,只需简单地每隔一段时间替换显示帧即可。以下是一个示例:

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 动作是一个很好的选择。此外,它也是给菜单和按钮添加动画的不错方法。

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, Director::getInstance()->getVisibleSize().height - mySprite->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_back, delay->clone(), nullptr);

// run the sequence and repeat forever.
mySprite->runAction(RepeatForever::create(seq1));

运行“开发者指南示例”中的这部分代码可以查看动作效果。

序列动作以及如何执行它

Sequence 可以使一系列的动作对象按顺序执行,这一系列对象可以是任意数量的动作对象、函数,甚至是另外一个序列动作。在 Cocos2d-x 中,有一个 CallFunc 对象,它允许我们创建一个 function() 函数并传递到 Sequence 中执行,这样就可以在序列动作对象中添加自定义的函数功能,而不局限于 Cocos2d-x 中提供的动作对象。

以下是一个序列动作的例子:

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 的作用与运行多个连续的 runAction() 语句所产生的结果相同,但使用 Spawn 的优点在于可以将其放到一个序列中,从而实现特定的效果,而 runAction() 无法做到这一点。将 SpawnSequence 结合使用可以实现很多强大的功能。

以下是一个例子:

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

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

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

两个方式产生的效果相同,但 Spawn 可以在 Sequence 中使用。以下是一个结合 SpawnSequence 的例子:

// 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 的作用如其名,当运行一系列动作时,可以调用 reverse() 函数使动作逆序执行。需要注意的是,这不仅仅是简单的逆序运行,实际上还会将原始的 SequenceSpawn 的属性也转换为逆序。

以下是一个使用 Reverse 的例子:

// 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
mySprite->runAction(sequence);

// reverse it
mySprite->runAction(sequence->reverse());

大部分 ActionSequence 对象都是可逆的。虽然 reverse() 使用起来简单,但逻辑上并不简单,不过 Cocos2d-x 已经为我们处理了这些复杂的逻辑。

作者信息

boke

boke

共发布了 3994 篇文章