cocos2dx——自制动作。shake your body!
来源:互联网 发布:数据录入员招聘58同城 编辑:程序博客网 时间:2024/04/19 07:41
(如有错误,请联系我更正,以免误导他人!)
cocos2dx中给我们封装好许许多多的动作,利用这些封装好的动作我们可以很容易地实现很多有趣的动作效果。但是,在实际开发中,cocos2dx中已经封装好的动作往往并不能满足我们的需求。这时候就需要我们自己来封装我们自己设计的动作。那么,要快速封装新的动作类,我们就必须了解cocos2dx中动作的原理。那么下面,我们就来简单了解下cocos2dx中的动作具体是怎么实现的。
首先,我们看到我们常用的动作类MoveBy、JumpBy。通过查看源码,break发现,他们都继承于同一个类:ActionInterval。而ActionInterval继承于FiniteTimeAction,FiniteTimeAction继承于Actionn。其中Action是所有动作类的基类。
ActionInterval其实是动作的一个大的分支,我们今天主要分析这个类型的动作的封装。在cocos2dx源码文档中对ActionInterval的描述如下:这是一个持续一段时间的动作。它有一个开始时间和一个结束时间,结束时间是开始时间+duration。其中duration是FiniteTimeAction类的成员变量,FiniteTimeAction类的作用就是来维护这个变量。
在封装动作类之前,我们还要了解下ActionManager。这是动作管理类,用来管理动作、执行动作等。我们知道,要实现一个动作效果,我们首先要创建一个动作,然后调用runAction函数来执行动作。那么runAction到底是怎么执行动作的呢?
runAction其实只有一个操作,把动作添加到动作管理器里面(ActionManger对象),动作的执行还是要经过动作管理器的操作。
当一个动作添加入动作管理器时,会马上调用动作的startWithTarget把动作与执行动作的对象进行绑定,在动作与对象绑定的同时,我们也可以对动作进一步的初始化。
在默认情况下(没改变动作管理器时,默认使用导演的动作管理器),“导演”(cocos2dx中由导演执行游戏的 大部分行为(刷新画面、初始化、结束游戏等),导演实则为一个单例)每一桢都调用动作管理器的update函数。
动作管理器的update函数遍历添加入管理器内的动作,判断动作是否需要执行,需要执行则调用动作的step函数。
在ActionInterval动作中,step负责计算动作的执行程度。计算结果是一个浮点值,它的范围为0~1。0代表刚动作刚开始,1代表动作执行完,以此类推0.5代表动作执行一半。然后,计算结果作为参数调用动作的update函数。(step函数一般不需要我们重写。)
动作的update函数就是动作的具体执行算法。
由上面的分析可知,我们要封装一个简单的ActionInterval类型的动作,只需要重写它的update、startWithDuration方法,再实现自己的初始化函数即可。下面,我们就一边上代码,一边更具体的讲解。
我们来封装一个晃动的动作,使元素在执行时间duration内(水平\竖直)晃动_shaketime次,每次晃动的距离为
_shakewidth。
<span style="font-size:18px;">class LShakeAction:public cocos2d::ActionInterval{private:int _shaketime;//晃动次数int _shakewidth;//晃动距离cocos2d::Vec2 _startpos;//起始点(执行对象的初始位置)ShakeDirection _shaked;//晃动方向};</span>
其中ShakeDirection定义如下:
<span style="font-size:18px;">enum ShakeDirection {HORIZONTAL,//水平方向VERTICAL//竖直方向};</span>
下面是成员函数:
<span style="font-size:18px;">public:static LShakeAction* create(float duration,int shaketime,int shakewidth, ShakeDirection shaked=ShakeDirection::HORIZONTAL);virtual LShakeAction* clone() const override;virtual void startWithTarget(cocos2d::Node* target) override;virtual void update(float time) override;public:LShakeAction();virtual ~LShakeAction();private:bool initWithDuration(float duration, int shaketime, int shakewidth, ShakeDirection shaked);CC_DISALLOW_COPY_AND_ASSIGN(LShakeAction);//禁用拷贝构造与=运算符</span>
create函数定义:
<span style="font-size:18px;">LShakeAction * LShakeAction::create(float duration, int shaketime, int shakewidth, ShakeDirection shaked){auto action = new(std::nothrow) LShakeAction;if (action&&action->initWithDuration(duration, shaketime, shakewidth, shaked)){action->autorelease();return action;}return nullptr;}</span>
这个函数相信小伙伴们都很熟悉了,创建对象,调用对象初始化函数,把对象加入自动回收池(详情见《cocos2dx内存管理》:http://blog.csdn.net/qq_28290581/article/details/52201752)。由create函数的声明可以看到,默认的晃动方向是HORIZONTAL(水平方向)。
initWithDuration函数定义:
<span style="font-size:18px;">bool LShakeAction::initWithDuration(float duration, int shaketime, int shakewidth, ShakeDirection shaked){if (shaketime <= 0)return false;if (!ActionInterval::initWithDuration(duration) || shaketime <= 0)return false;_shaketime = shaketime;_shakewidth = shakewidth;_shaked = shaked;return true;}</span>
调用父类的initWithDuration初始化FiniteTimeAction中的_duration(动作执行时间)成员变量。然后给成员变量_shaketime、_shakewidth、_shaked赋值。
clone函数:
<span style="font-size:18px;">LShakeAction * LShakeAction::clone() const{return LShakeAction::create(_duration, _shaketime, _shakewidth, _shaked);}</span>
克隆动作。
startWithTarget函数:
<span style="font-size:18px;">void LShakeAction::startWithTarget(cocos2d::Node * target){ActionInterval::startWithTarget(target);_startpos = target->getPosition();}</span>
调用父类的startWithTarget并记录动作执行对象的初始位置。
update函数定义(主角来了):
<span style="font-size:18px;">void LShakeAction::update(float time){if (_target) {float frac = fmodf((time*_shaketime), 1.0f);float movedistance = moveSign(frac)*fmodf(frac, 0.25f)*_shakewidth;Vec2 newpos = _startpos;if (_shaked == ShakeDirection::HORIZONTAL)newpos.x += movedistance;elsenewpos.y += movedistance;_target->setPosition(newpos);}}</span>
由前面的分析知,参数time是由step函数计算并传递的,它代表动作执行的程度。time*shaketime的整数部分+1就是当前对象正在进行的晃动的次数,小数部分就是这次晃动执行的具体到的程度。上个简图:假设当前晃动3次。
由此可知,frac的值就是当前晃动的执行程度。
假设晃动是水平晃动,当shakewidth为正数时,物体先往右边移动(负数则相反),当移动到startpos.x(物体初始位置的x坐标)+shakewidth时改变移动方向,当物体移动到startpos.x-shakewidth时又改变方向,最后,当物体回到初始位置时,则完成一次晃动。所以,我们可以把物体的整个晃动分解成4段:
第一段:从startpos.x移动到shartpos.x+shakewidth(初始方向)
第二段:从shartpos.x+shakewidth移动到startpos.x(移动方向与初始方向相反)
第三段:从startpos.x移动到startpos.x-shakewidth(移动方向与初始方向相反)
第四段:从startpos.x-shakewidth移动到startpos.x。(移动方向与初始方向相同)
movedistance即是当前调用update后物体需要到移动的位置距初始位置的距离。其中fmodf(frac, 0.25f)的计算结果与frac的计算结果类似,把当前晃动拆分为4段,并得出当前段的执行程度。fmodf(frac, 0.25f)*_shakewidth就得出了movedistance的绝对值。再通过对移动方向的判断(乘以moveSign(frac)(移动方向与初始方向相同为正,移动方向与初始方向相反为负)得出movedistance,其中moveSign函数定义如下:
static int moveSign(float frac) {int res = frac / 0.25f;switch (res){case 0:case 3:case 4:return 1;case 1:case 2:return -1;}return 0;}
计算好movedistance之后,我们只需要判断shaked为HORIZONTAL(水平)或者为VERTICAL来判断是对物体的x坐标还是y坐标进行操作就行了。
完整代码下载:http://download.csdn.net/detail/qq_28290581/9609876
- cocos2dx——自制动作。shake your body!
- Cocos2dx—动作类Action
- cocos2dx学习笔记(三)——动作(CCAction)
- [cocos2dx]抽象元素——CCAction动作类
- cocos2dx 动作
- Cocos2dX动作
- cocos2dx-动作
- Cocos2dx技术(三)——cocos2dx基本概念(四)动作
- shake
- SHAKE
- shake
- cocos2dx 精灵动作优化
- cocos2dx 49种动作
- cocos2dx常见动作
- cocos2dx 动作详解
- cocos2dx-Action动作
- cocos2dx创建精灵动作
- cocos2dx-Action动作
- h5 audio播放音频文件
- [图形学] 光线追踪中的数学方法
- 在tableview上添加悬停窗口
- Cadence 学习笔记 - Capture CIS 篇 (ERROR (ORCAP - 1228) )
- python中的range()和array()函数
- cocos2dx——自制动作。shake your body!
- 【华为练习题 】 长寿的兔子
- Properties集合的应用
- Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE
- 关于栈区、堆区、全局区、常量区、代码区的总结
- Axis2与Spring集成发布
- qt quick 开发实战——qt 多文档编辑器
- 读书笔记-Linux C 编程从基础到实践-第二章 在Linux下进行C语言开发
- AngularJS中的双向数据绑定 ng-bind,ngshow,ng-hide,ng-class,ngAnimate