代码例子
m_pActionSprite = Sprite::create("CloseSelected.png");
m_pActionSprite->setPosition(100.0f,100.0f);
addChild(m_pActionSprite);
m_pActionSprite->runAction(MoveBy::create(10.0f, Vec2(500.0f,500.0f)));
效果
分析
分为两个过程
1.构建Action
2.在渲染循环中(Director::mianLoop -> Director::drawScene)中执行每一帧
构建Action过程
runAction主要做了两件事情
1.在Direction Scheduler 中的 ActionManager中addAction
ActionManager维护了一个数组(c语言),每一个Element的结构如下
也就是说一个Node对象,会维持一个Action的Array
2.另外create出的Action进行了保存。在ActionManager中首先找到target,然后找到target下的Action,然后调用Action去执行具体的动画。
Action本身是一个完整的动作描述,包括了target对象,在update中具体实现帧动画
对于MoveBy初始化有两个方面比较重要:
1.在create的时候
记录了duration和增量值
2.在调用target的runAction时候,ActionManager中add了Action后,会调用startWithTarget
关键是Action保存了要执行的Node对象,另外初始化了
1.position-通过target获取
2.duration 0
3.elapsed 0
4.firstTick true
Action渲染过程
1.在Director::drawScen中
_deltaTime 如何来的?
在drawScene中首先调用了
calculateDeltaTime();
最后*_lastUpdate = now;
排除意外情况后,真正的计算时间是:
_deltaTime = (now.tv_sec - _lastUpdate->tv_sec) + (now.tv_usec - _lastUpdate->tv_usec) / 1000000.0f;
tv_sec 是秒单位
tv_used是微秒单位
1秒=100万微秒
tv_sec: 1s
tv_used: 500 000 us
两者相加是 1.5秒
2.在scheduler::update中,遍历了添加到scheduler中的element,并调用其对应的回调
其中ActionManager回调的添加是在Director::init中发生的
我们看看scheduleUpdate
target此处代表了ActionManager对象,priority,此处要注意,ActionManager设定的是最小的值(也就是在schedule::update中首先执行的是ActionManager的update回调方法)
3.在ActionManager::update中遍历每一个Element,然后遍历该target的每一个Action,然后调用了Action::step
针对MoveBy来说,调用的是ActionInterval::step
4.最终调用了MoveBy的update
上图代码的原理主要参考了:http://www.cocoachina.com/bbs/3g/read.php?tid=288130
当只有一个动作作用于精灵时,currentPos与_previousPosition一直都是相同的(因为没有其他动作移动该精灵),所以diff总是为0,继而精灵的起始坐标(_startPosition)保持不变,精灵只是_positionDelta * t计算出当前精灵应该移动的偏移量。针对以上的描述举一个简单的例子,比如一个MoveBy动作是1s向右移动100个像素,现在调用了update(),时间过去了0.1秒,那么此时应该将精灵放在距离起始坐标向右10个像素的位置(_startPosition + (100, 0) * 0.1);之后过了段时间又掉用了update(),此时过去了0.7秒,那么此时应该将精灵放在距离起始坐标向右70个像素的位置。
当有多个动作作用于精灵时情况稍微复杂了些。比如有两个MoveBy动作都是1s向右移动100个像素,精灵的起始位置是(0, 0),0.1s的时候MoveBy1的update()被调用,将精灵向右移动了10个像素,此时精灵位于(10, 0);0.11s时MoveBy2的update()被调用,发现精灵的当前位置与自己之前记录的起始坐标(_previousPosition,startWithTarget()中初始化了)不一样了,故而_startPosition被更新为(10, 0),之后将精灵向右移动11个像素,此时精灵位于(21, 0);之后比如0.15s时MoveBy1的update()被调用,也发现精灵的当前位置与自己之前记录的起始坐标不一样了,故而_startPosition被更新为(11, 0),之后将精灵向右移动15个像素,此时精灵位于(26, 0);之后就是以此类推,当1s过后精灵位于(200, 0)。
当不开启CC_ENABLE_STACKABLE_ACTIONS时,update()中只有一个setPosition(),所以谁最后setPosition()就体现谁的效果,即最后一个MoveBy有效果。