Action是动作的基类,所有的动作都派生自这个类,它创建的一个对象代表了一个动作。动作作用于Node,因此,任何一个动作都需要由Node对象来执行。
// 将一个精灵用3秒钟时间从屏幕中间移动到(0, 0)的位置
auto tortoise = Sprite::create("other/tortoise.png");
tortoise->setPosition(Vec2(visibleSize.width/2 + visibleOrigin.x, visibleSize.height/2 + visibleOrigin.y));
this->addChild(tortoise);
auto action = MoveTo::create(3.0f, Vec2(0 + visibleOrigin.x, 0 + visibleOrigin.y));
tortoise->runAction(action);
一个Action只能使用一次,这是因为动作对象不仅描述了动作,还保存了这个动作持续过程中不断改变的一些中间参数。
Action作为一个基类,其实质是一个接口(抽象类),由它派生的实现类(如运动和转动等)才是我们实际使用的动作。Action的绝大多数实现类都派生自Action的子类FiniteTimeAction,这个类定义了在有限时间内可以完成的动作。FiniteTimeAction定义了reverse方法,通过这个方法可以获得一个与原动作相反的动作(逆动作),例如隐藏一个精灵后,用逆动作再显示出来。并非所有的动作都对应有逆动作,例如类似“放大到”等设置属性为常量的动作不存在逆动作,而设置属性为相对值的动作则往往存在相应的逆动作。
FiniteTimeAction派生出的两个主要类分别是瞬时动作ActionInstant和持续性动作ActionInterval。
瞬时动作指能够立刻完成的动作,是FiniteTimeAction中动作持续时间为0的特例。这类动作是在下一帧会立刻执行并完成的动作,如设定位置、设定缩放等。这类动作原本可以通过简单地对Node赋值完成,但是把它们包装为动作后,可以方便地与其他动作类组合为复杂动作。
1.一些常用的瞬时动作:
Place
该动作用于将节点放置到某个指定位置,其作用于修改节点的Position属性相同。// 将精灵放到屏幕坐标(200, 200)处
auto placeAction = Place::create(Vec2(200, 200));
tortoise->runAction(placeAction);
FlipX和FlipY
这两个动作分别用于将精灵沿X和Y轴反向显示,其作用与设置精灵的FlipX和FlipY属性相同。// 将精灵沿X轴反转
auto flipXAction = FlipX::create(true);
tortoise->runAction(flipXAction);
Show和Hide
这两个动作分别用于显示和隐藏节点,其作用和设置节点的visible属性相同。// 隐藏精灵
auto hideAction = Hide::create();
tortoise->runAction(hideAction);
CallFunc
CallFunc系列动作包括__CCCallFuncND,__CCCallFuncO,CallFuncN,用来在动作中进行函数调用。当某个对象执行CallFunc系列动作时,就会调用一个事先被设置好的方法,以完成某些特别的功能。CallFunc系列动作的后缀“N”表示Node参数,指的是执行动作的对象,“D”表示Data参数,指的是用户自定义的数据,“O”表示对象,指的是一个用户自定义的Object(Ref)参数。
// 在动作中进行函数调用,可以是类成员函数,也可以是普通函数
// void fun(Node *node) 普通函数
void HelloWorld::fun(Node *node)
{
CCLOG("CallFuncN");
}
// auto callFuncAction = CallFuncN::create(fun); 在动作中调用普通函数
auto callFuncAction = CallFuncN::create(this, callfuncN_selector(HelloWorld::fun)); // 动作中调用类成员函数
tortoise->runAction(callFuncAction);
2.持续性动作是在持续的一段时间里完成的动作,绝大多数持续性动作都会带有一个用于控制动作执行时间的实型参数duration。每一种持续性动作通常都存在两个不同的变种动作,分别具有To和By后缀:后缀为To的动作描述了节点属性值的绝对变化,例如MoveTo将对象移动到一个特定的位置;而后缀为By的动作描述了属性值的相对变化,如MoveBy将对象移动一段相对位移。
根据作用效果不同,可以将持续性动作划分为一下4大类:位置变化动作,属性变化动作,视觉特效动作,控制动作。
位置变化动作
针对位置(position)属性,引擎为我们提供了3种位置变化动作类型。MoveTo和MoveBy用于使节点做直线运动。
// 在规定时间内,从当前位置直线移动到设定的终点位置
auto moveToAction = MoveTo::create(3.0f, Vec2(0, 0));
tortoise->runAction(moveToAction);
// 在规定时间内,相对当前位置移动(100, 100),效果是往右上角移动
auto moveByAction = MoveBy::create(3.0f, Vec2(100, 100));
tortoise->runAction(moveByAction);
JumpTo和JumpBy使节点以一定的轨迹跳跃到指定位置
// 在规定时间内,从当前位置跳跃到设定的终点位置,第一个参数表示持续时间,第二个参数表示移动的终点位置,第三个表示跳跃最大高度,第四个参数表示跳跃次数
auto jumpToAction = JumpTo::create(3.0f, Vec2(0, 0), 50.0f, 5);
tortoise->runAction(jumpToAction);
// 在规定时间内,相对当前位置跳跃(300, 300),效果是往右上角跳跃
auto jumpByAction = JumpBy::create(3.0f, Vec2(300, 300), 50.0f, 5);
tortoise->runAction(jumpByAction);
BezierTo和BezierBy使节点进行曲线运动,运动轨迹由贝塞尔曲线描述。每一个贝塞尔曲线都包含一个起点和一个终点。在一条曲线中,起点和终点都各自包含一个控制点,而控制点到端点的连线称作控制线。控制线决定了从端点发出的曲线的形状,包含角度和长度两个参数,角度决定了它所控制的曲线的方向,即这段曲线在这一控制点的切线方向,长度控制曲线的曲率。控制线越长,它所控制的曲线离控制线越近。任意一段曲线都可以由一段或几段相连的贝塞尔曲线组成。
// 使用时需要先创建ccBezierConfig结构体,设置好终点endPosition以及两个控制点controlPoint_1和controlPoint_2后,再把结构体传入BezierTo或BezierBy的初始化方法中
ccBezierConfig bezier;
bezier.controlPoint_1 = Vec2(20, 150);
bezier.controlPoint_2 = Vec2(200, 30);
bezier.endPosition = Vec2(160, 30);
auto bezierToAction = BezierTo::create(3.0f, bezier);
tortoise->runAction(bezierToAction);
属性变化动作
通过属性值的逐渐变化来实现动画效果。ScaleTo和ScaleBy产生缩放效果
// 第二个参数为缩放系数
auto scaleToAction = ScaleTo::create(3.0f, 2);
tortoise->runAction(scaleToAction);
RotateTo和RotateBy产生旋转效果
// 第二个参数是角度,正方向为顺时针
auto rotateToAction = RotateTo::create(3.0f, 30.0f);
tortoise->runAction(rotateToAction);
FadeIn和FadeOut前者实现淡入效果,后者实现淡出效果
FadeTo设置一段时间内透明度的变化效果
TintTo和TintBy设置色调变化
只有实现了CCRGBAProtocol接口的节点才可以执行这类动作,这是因为与透明度或颜色相关的属性都继承自CCRGBAProtocol接口。许多常见的节点,如Sprite和LayerColor等,都实现了这个接口。// 用持续时间和不透明度创建动作,第二个参数GLubyte类型是8位无符号整数,因此可取0-255中的任意整数,与透明度有关的动作只能应用在精灵上,且子节点不受父节点影响。
auto fadeToAction = FadeTo::create(3.0f, 100);
tortoise->runAction(fadeToAction);
// rgb取值范围为0-255
TintTo::create(float duration, GLubyte red, GLubyte green, GLubyte blue);
TintBy::create(float duration, GLshort deltaRed, GLshort deltaGreen, GLshort deltaBlue);
视觉特效动作
Blink使目标节点闪烁
// 3秒内闪烁5次
auto blinkAction = Blink::create(3.0f, 5);
tortoise->runAction(blinkAction);
Animate播放帧动画
控制动作
控制动作用于对动作进行精细控制。DelayTime将动作延续一段时间。
Repeat把现有动作重复一定次数。
RepeatForever使一个动作不断重复下去。
3.复合动作
组合各种基本动作来产生复杂的动作效果。Repeat和RepeatForever
// 重复动作
auto repeatAction = Repeat::create(blinkAction, 3);
tortoise->runAction(repeatAction);
Spawn并列动作
一批动作同时执行。执行的动作必须是能够同时执行的、继承自FiniteTimeAction的动作。组合后Spawn最终完成时间是由其成员中最大执行时间的动作来决定。Sequence序列动作
按顺序执行一系列动作。部分非延时动作不被支持,如RepeatForever。DelayTime延时动作
表示动作序列里的一段空白期,通过占位的方式将不同的动作串接在一起,什么都不做。4.变速动作
Speed用于线性的改变某个动作的速度,使动作持续更长或更短的时间。Speed动作不能作为一个动作序列的一部分, 因为它不是一个ActionInterval对象。
// 改变MoveTo动作的速度
auto moveToAction = MoveTo::create(10.0f, Vec2(100, 100));
// 两个参数分别为目标动作和变速比率,设置变速比率为1,目标动作的速度不会被改变
auto speedAction = Speed::create(moveToAction, 1);
// 设置动作的tag属性,与Node的tag属性类似,用于方便查找动作
speedAction->setTag(0);
sprite->runAction(speedAction);
// 设置一个定时器,4秒后将MoveTo动作速度变为原来的10倍
this->scheduleOnce(schedule_selector(HelloWorld::changeSpriteSpeed), 4);
// 定时器实现
void HelloWorld::changeSpriteSpeed(float data)
{
Speed *speed = dynamic_cast<Speed *>(sprite->getActionByTag(0));
speed->setSpeed(10);
}
ActionEase
Speed只能按比例改变目标动作的速度,如果我们要实现动作由快到慢、速度随时间改变的变速运动,需要不停地修改它的speed属性才能实现。而ActionEase系列动作通过使用内置的多种自动速度变化来解决这一问题。ActionEase动作可以被概括为5类动作:指数缓冲、Sine缓冲、弹性缓冲、跳跃缓冲和回震缓冲。每一类动作都有3个不同时期的变化:In、Out和InOut。
auto moveToAction = MoveTo::create(10.0f, Vec2(100, 100));
auto easeSineInAction = EaseSineIn::create(moveToAction);
tortoise->runAction(easeSineInAction);