Cocos2d-x 学习笔记(11.6) Sequence
1. Sequence
动作序列。动作按参数顺序执行,动作总时长为每个动作的时长之和。
1.1 成员变量
FiniteTimeAction *_actions[2]; float _split; // 第一个action在Sequence的时间占比 int _last;
1.2 create方法
4种:
createWithTwoActions(FiniteTimeAction *actionOne, FiniteTimeAction *actionTwo) // 用两个action创建 create(FiniteTimeAction *action1, ...) // 用很多action创建,调用下面的方法 createWithVariableList(FiniteTimeAction *action1, va_list args) create(const Vector<FiniteTimeAction*>& arrayOfActions) // 存储action的Vector容器作为参数
createWithTwoActions:
调用initWithTwoActions方法,两个action的时间之和作为Sequence的duration,并对两个action retain()。
createWithVariableList:
调用了createWithTwoActions方法,参数第一个action为参数action,参数第二个action为va_list args存储的变长参数。当只有一个action时,createWithTwoActions的第二个参数为ExtraAction。
Sequence* Sequence::createWithVariableList(FiniteTimeAction *action1, va_list args) { FiniteTimeAction *now; FiniteTimeAction *prev = action1; bool bOneAction = true; while (action1) { now = va_arg(args, FiniteTimeAction*); if (now) { prev = createWithTwoActions(prev, now); bOneAction = false; } else { // If only one action is added to Sequence, make up a Sequence by adding a simplest finite time action. if (bOneAction) { prev = createWithTwoActions(prev, ExtraAction::create()); } break; } } return ((Sequence*)prev); }
create:
使用Vector存储action,调用init方法,递归地创建Sequence。
s1=a1+a2 s2=a3+s1 s3=a4+s2 s4=a5+s3 ... 最终获得的Sequence是一个action和sequence的组合。
1.3 startWithTarget
runAction时调用。
if (_duration > FLT_EPSILON) _split = _actions[0]->getDuration() > FLT_EPSILON ? _actions[0]->getDuration() / _duration : 0;
ActionInterval::startWithTarget(target);
_last = -1;
_duration和action的duration要大于精度值FLT_EPSILON,第一个action的设置时间与序列总时间的商是_split,代表第一个action在序列上的时间占比。
_last是上次序列update时执行的action下标,0或1,-1代表还未update。
1.4 update
简而言之,update通过当前进度判断要执行哪个action,先计算好这个action的本次进度。如果本次是第一次执行第二个action,要先把第一个action update执行完成。接下来,执行这次的action update,执行后保存这次执行的下标,供下一帧判断。
Sequence对嵌套其中的Sequence递归执行startWithTarget和update。递归退出的条件是found == _last && _actions[found]->isDone(),即最后一个action执行完成。
1 void Sequence::update(float t) 2 { 3 int found = 0; // 当前action下标 4 float new_t = 0.0f; // 当前action进度 5 6 if( t < _split ) // 正在执行第一个action 7 { 8 // action[0] 9 found = 0; // 改变下标 10 if( _split != 0 ) // 第一个action设置的时间不为0 11 new_t = t / _split; // 计算第一个action进度 12 else 13 new_t = 1; // 第一个action设置的时间为0,则完成第一个action 14 15 } 16 else // 正在执行第二个action 17 { 18 // action[1] 19 found = 1; // 改变下标 20 if ( _split == 1 ) // 第二个action时间为0时 21 new_t = 1; // 完成第二个action 22 else 23 new_t = (t-_split) / (1 - _split ); // 计算第二个action进度 24 } 25 26 if ( found==1 ) // 正在执行第二个Action 27 { 28 if( _last == -1 ) // 如果上一次update没有执行第一个action 29 { 30 // action[0] was skipped, execute it. 31 _actions[0]->startWithTarget(_target); // 初始化第一个action 32 if (!(sendUpdateEventToScript(1.0f, _actions[0]))) 33 _actions[0]->update(1.0f); // 直接完成第一个action 34 _actions[0]->stop(); 35 } 36 else if( _last == 0 ) // 上次update执行的是第一个action,本次update执行第二个,说明第一个执行完成 37 { 38 // switching to action 1. stop action 0. 39 if (!(sendUpdateEventToScript(1.0f, _actions[0]))) 40 _actions[0]->update(1.0f); // 让第一个执行完成 41 _actions[0]->stop(); 42 } 43 } 44 else if(found==0 && _last==1 ) // 基本不会发生的情况 45 { 46 // Reverse mode ? 47 // FIXME: Bug. this case doesn't contemplate when _last==-1, found=0 and in "reverse mode" 48 // since it will require a hack to know if an action is on reverse mode or not. 49 // "step" should be overridden, and the "reverseMode" value propagated to inner Sequences. 50 if (!(sendUpdateEventToScript(0, _actions[1]))) 51 _actions[1]->update(0); 52 _actions[1]->stop(); 53 } 54 // Last action found and it is done. 55 if( found == _last && _actions[found]->isDone() ) 56 { 57 return; 58 } 59 60 if( found != _last ) // 正常执行到新的action 61 { 62 _actions[found]->startWithTarget(_target); // 新action初始化 63 } 64 if (!(sendUpdateEventToScript(new_t, _actions[found]))) 65 _actions[found]->update(new_t); // 执行 66 _last = found; // 记录这次执行的action下标 67 }