菜鸟学习Cocos2d-x 3.x——浅谈动作Action动作类概述一款游戏,设计的再NB的游戏,如果都是一堆静态的图片,没有任何动作,那也只能“呵呵”了。
动作体系对于一款游戏的成功与否,有着非常重要的影响。
所以,这篇文章就对Cocos2d-x中的动作进行总结。
先来看看Cocos2d-x中的与动作相关的类。
与动作相关的类图如下图所示:现在就对这些类进行简单的介绍,在后续的小节中还会进行详细的分析的。
∙Ref和Clonable:这里不说,在总结Cocos2d-x内存管理的时候再进行详细总结;∙Action:所有动作的父类,定义了公共的操作;∙FiniteTimeAction:瞬时动作和延时动作的父类,可以定义动作的时间变化;∙Follow:跟随节点的动作;∙Speed:改变一个动作的时间,比如实现慢动作回放或者快进;∙ActionInstant:瞬间完成动作,中间没有任何动画效果;∙ActionInterval:动作会在指定的时间内完成,中间会有动画效果;∙FlipX:X轴方向翻转;∙MoveTo:移动动作;∙……下面就对上面说的这些类进行通过实际的代码进行总结。
Action类的主要成员函数以下是Action类的主要成员函数:/*** 返回一个新的Action对象,表示原动作的相反的动作*/virtual Action* reverse()const=0;// 如果动作已经完成了,就返回truevirtualbool isDone()const;// 在动作开始之前被调用,设置动作作用的对象virtualvoid startWithTarget(Node*target);/*** 在动作完成以后会被调用,它会设置"target"对象为空* 注:请永远不要手动调用该函数,而是调用对应的"target->stopAction(a ction);"*/virtualvoid stop();/*** 每帧都会调用的方法,如果你需要在每帧控制动作,则需要重写,时间间隔为动作间隔时间* 最好不要重写该函数,除非你真的知道怎么做*/virtualvoid step(float dt);/*** 每一帧都会调用一次该函数,参数time取值为0和1之间的任意值,例如:* 0表示动作刚刚开始的时候调用;* 0.5表示动作执行到一半的时候调用;* 1表示动作完成以后调用;*/virtualvoid update(float time);// 获得执行动作的对象inline Node*getTarget()const{return _target;}// 设置执行动作的对象inlinevoid setTarget(Node*target){ _target = target;}// 动作标签inlineint getTag()const{return _tag;}inlinevoid setTag(int tag){ _tag = tag;}瞬时动作ActionInstant是瞬时动作类。
瞬时动作表示瞬间完成动作,中间没有任何动画效果;由于ActionInstant的子类那么多,这里就以FlipX为例子,做一个简单的Demo。
效果如下图所示:可以看到小狗走到最左边时,会有一个转向的过程,这就是FlipX的动作效果。
示例代码如下:Size visibleSize=Director::getInstance()->getVisibleSize();// 创建移动动作ActionInterval*moveto=MoveTo::create(5,Vec2(0,200));// 创建X轴方向的翻转动作ActionInstant*flipx=FlipX::create(true);ActionInterval*moveback=MoveTo::create(5,Vec2(visibleSize.widt h,200));auto scene =Director::getInstance()->getRunningScene();auto layer = scene->getChildByTag(1);auto dog = layer->getChildByTag(1);// flipx->reverse()获得对应的逆向动作auto action =Sequence::create(moveto,flipx,moveback,flipx->reve rse(), NULL);dog->runAction(action);瞬时动作是只能够立刻完成的动作,这类动作是在下一帧立刻完成的动作,如设定位置、设定缩放等。
把它们包装成动作后,可以与其他动作类组合为复杂动作。
延时动作动作会在指定的时间内完成,中间会有动画效果。
延时动作通过属性值的逐渐变化来实现动画效果。
需要注意的是XXTo和XXBy的区别在于XXTo是表示最终值,而XXBy则表示向量-改变值。
比如MoveTo和MoveBy动作,如以下效果所示:示例代码如下:// 创建移动动作ActionInterval*moveto=MoveTo::create(5,Vec2(0,200)); ActionInterval*moveby=MoveBy::create(5,Vec2(-200,0));auto scene =Director::getInstance()->getRunningScene();auto layer = scene->getChildByTag(1);auto dog1 = layer->getChildByTag(1);auto dog2 = layer->getChildByTag(2);dog1->runAction(moveto);dog2->runAction(moveby);上面的那只狗是使用的MoveBy动作,而下面这只狗使用的是MoveTo动作。
MoveTo 动作都在用,下面就来看看稍微复杂点的贝塞尔曲线动作。
使用贝塞尔曲线,可以使节点进行曲线运动。
每条贝塞尔曲线都包含一个起点和一个终点。
在一条曲线中,起点和终点各自包含一个控制点,而控制点到端点的连线称作控制线。
控制点决定了曲线的形状,包含角度和长度两个参数。
如下图:实现效果如下:示例代码如下:ccBezierConfigbezier;bezier.controlPoint_1 =Point(200,300);bezier.controlPoint_2 =Point(400,400);bezier.endPosition=Point(50,200);auto bezierAction=BezierTo::create(2.0f,bezier);dog1->runAction(bezierAction);我们在实际开发中,主要的任务就是确定两个控制点,去协调精灵的移动弧度。
缓冲动作在游戏中,我们经常要实现一些加速度或者减速度的效果。
Cocos2d-x已经为我们做好了。
ActionEase类可以实现动作的速度由快到慢、速度随时间改变的匀速运动。
该类包含5类运动:∙指数缓冲;∙Sine缓冲;∙弹性缓冲;∙跳跃缓冲;∙回震缓冲。
每类运动都包含3个不同时期的变换:In、Out和InOut。
∙In表示开始的时候加速;∙Out表示结束的时候加速;∙InOut表示开始和结束的时候加速。
上述5类运动分别对应以下的类:∙指数缓冲:EaseExponentialIn、EaseExponentialOut和EaseExponentialInOut;∙Sine缓冲:EaseSineIn、EaseSineOut和EaseSineInOut;∙弹性缓冲:EaseElasticIn、EaseElasticOut和EaseElasticInOut;∙跳跃缓冲:EaseBounceIn、EaseBounceOut和EaseBounceInOut;∙回震缓冲:EaseBackIn、EaseBackOut和EaseBackInOut。
通过图表和描述也不能形象的说明上述5中运动,下面就通过指数缓冲的实际运行效果来进行展示:指数缓冲示例代码如下:ActionInterval*moveto1 =MoveTo::create(5,Vec2(50,100)); ActionInterval*moveto2 =MoveTo::create(5,Vec2(50,300)); ActionInterval*moveto3 =MoveTo::create(5,Vec2(50,500));auto scene =Director::getInstance()->getRunningScene();auto layer = scene->getChildByTag(1);auto dog1 = layer->getChildByTag(1);auto dog2 = layer->getChildByTag(2);auto dog3 = layer->getChildByTag(3);auto action1 =EaseExponentialIn::create(moveto1);auto action2 =EaseExponentialOut::create(moveto2);auto action3 =EaseExponentialInOut::create(moveto3);dog1->runAction(action1);dog2->runAction(action2);dog3->runAction(action3);从下到上的三次小狗,分别对应的是EaseExponentialIn、EaseExponentialOut和EaseExponentialInOut。
∙EaseExponentialIn表现的效果为速度越来越快;∙EaseExponentialOut表现的效果为速度越来越慢;∙EaseExponentialInOut表现的效果为中间速度非常快,两头速度较慢。
组合动作在游戏中,很多时候,一个对象并不是单纯的执行一个动作,而是依次执行一系列动作或者同时执行一系列动作,那么这又该如何去完成呢?现在就来看看Cocos2d-x中是如何去完成这些的吧。
∙Sequence 可以使用Sequence定义一个动作序列,应用实例可以参见瞬时动作这小节。
∙Spawn Spawn也是定义一系列动作,但是定义的动作会同时执行,使用方法同Sequence是一样的。