ActionInterval
延时动作
路径 1 2 2 d/actions/ActionInterval.h2 d/actions/ActionInterval.cpp
源码 根据分析ActionInstant的经验,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 class CC_DLL ActionInterval : public FiniteTimeAction{ public : inline float getElapsed (void ) { return _elapsed; } void setAmplitudeRate (float amp) ; float getAmplitudeRate (void ) ; virtual bool isDone (void ) const override ; virtual void step (float dt) override ; virtual void startWithTarget (Node *target) override ; virtual ActionInterval* reverse () const override = 0 ; virtual ActionInterval *clone () const override = 0 ; protected : bool initWithDuration (float d) ; float _elapsed; bool _firstTick; }; bool ActionInterval::initWithDuration(float d){ _duration = d; if (_duration == 0 ) { _duration = FLT_EPSILON; } _elapsed = 0 ; _firstTick = true ; return true ; } bool ActionInterval::isDone(void ) const { return _elapsed >= _duration; } void ActionInterval::step(float dt){ if (_firstTick) { _firstTick = false ; _elapsed = 0 ; } else { _elapsed += dt; } this ->update(MAX(0 , MIN(1 , _elapsed / MAX(_duration, FLT_EPSILON) ) ) ); } void ActionInterval::startWithTarget(Node *target){ FiniteTimeAction::startWithTarget(target); _elapsed = 0.0f ; _firstTick = true ; }
和ActionInstant类似,ActionInterval也是在step中调用update。
有些功能性延时动作十分常用:
Sequence
Repeat
RepeatForever
Spawn (直接多次runAction)
Animate
除此之外,就是视觉性延时动作
MoveTo
MoveBy
RotateTo
RotateBy
SnewTo
SnewBy
JumpTo
JumpBy
BezielTo
BezierBy
ScaleTo
ScaleBy
Blink
FadeIn
FadeOut
FadeTo
TintTo
TintBy
DelayTime
ReverseTime
继承自FiniteTimeAction,什么都没实现,在Sequence,Spawn里作为一个结束动作。
PS : 默认Action的isDone返回的是true
Sequence 首先,我们来看看一个Sequence是怎么执行的?
例如有如下一个Sequence:
1 [[[[A0, A1], A2] A3] ExtraEnd]
S0 = [A0, A1]
S1 = [S0, A2]
S2 = [S1, A3]
S3 = [S2, ExtraEnd]
其中An表示延时任务
ExtraEnd表示ExtraAction
Sn表示Sequence
所以执行S3的执行流程如下
执行S3的第一个Action (S2)
执行S3的第二个Action (ExtarEnd)
执行过程有点递归的意思。 执行S2的时候需要执行S1和A3。然后执行S1的时候需要执行S0和A2。执行S0的时候需要执行A0和A1。 所以,执行的顺序还是A0 -> A1 -> A2 -> A3 -> ExtraEnd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 */ class CC_DLL Sequence : public ActionInterval{ public : static Sequence* create (FiniteTimeAction *action1, ...) CC_REQUIRES_NULL_TERMINATION ; * @code * When this funtion bound to the js or lua,the input params changed * in js :var create(var object1,var object2, ...) * in lua :local create(local object1,local object2, ...) * @endcode */ static Sequence* create (const Vector<FiniteTimeAction*>& arrayOfActions) ; static Sequence* createWithVariableList (FiniteTimeAction *action1, va_list args) ; static Sequence* createWithTwoActions (FiniteTimeAction *actionOne, FiniteTimeAction *actionTwo) ; virtual Sequence* clone () const override ; virtual Sequence* reverse () const override ; virtual void startWithTarget (Node *target) override ; virtual void stop (void ) override ; virtual void update (float t) override ; CC_CONSTRUCTOR_ACCESS: Sequence() {} virtual ~Sequence(void ); bool initWithTwoActions (FiniteTimeAction *pActionOne, FiniteTimeAction *pActionTwo) ; protected : FiniteTimeAction *_actions[2 ]; float _split; int _last; private : CC_DISALLOW_COPY_AND_ASSIGN(Sequence); };
先看看初始化方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 bool Sequence::initWithTwoActions(FiniteTimeAction *actionOne, FiniteTimeAction *actionTwo){ CCASSERT(actionOne != nullptr , "" ); CCASSERT(actionTwo != nullptr , "" ); float d = actionOne->getDuration() + actionTwo->getDuration(); ActionInterval::initWithDuration(d); _actions[0 ] = actionOne; actionOne->retain(); _actions[1 ] = actionTwo; actionTwo->retain(); return true ; }
给Action增加引用计数,设置了Sequence的时间。
当我们让一个对象runAction(Sequence)的时候,最先调用以下代码
1 2 3 4 5 6 void Sequence::startWithTarget(Node *target){ ActionInterval::startWithTarget(target); _split = _actions[0 ]->getDuration() / _duration; _last = -1 ; }
这里计算出_split的值,也就是两个Action之间的分割线 =。=
注意在startWithTarget中没有调用两个Action的startWithTarget(在update中调用)
然后再来看看update方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 void Sequence::update(float t){ int found = 0 ; float new_t = 0.0f ; if ( t < _split ) { found = 0 ; if ( _split != 0 ) new_t = t / _split; else new_t = 1 ; } else { found = 1 ; if ( _split == 1 ) new_t = 1 ; else new_t = (t-_split) / (1 - _split ); } if ( found==1 ) { if ( _last == -1 ) { _actions[0 ]->startWithTarget(_target); _actions[0 ]->update(1.0f ); _actions[0 ]->stop(); } else if ( _last == 0 ) { _actions[0 ]->update(1.0f ); _actions[0 ]->stop(); } } else if (found==0 && _last==1 ) { _actions[1 ]->update(0 ); _actions[1 ]->stop(); } if ( found == _last && _actions[found]->isDone() ) { return ; } if ( found != _last ) { _actions[found]->startWithTarget(_target); } _actions[found]->update(new_t ); _last = found; }
通过分析以上代码,我们可以知道update在管理着这两个Action的开始和结束。
Repeat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class CC_DLL Repeat : public ActionInterval{ public : protected : unsigned int _times; unsigned int _total; float _nextDt; bool _actionInstant; FiniteTimeAction *_innerAction; private : CC_DISALLOW_COPY_AND_ASSIGN(Repeat); };
初始化函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 bool Repeat::initWithAction(FiniteTimeAction *action, unsigned int times){ float d = action->getDuration() * times; if (ActionInterval::initWithDuration(d)) { _times = times; _innerAction = action; action->retain(); _actionInstant = dynamic_cast <ActionInstant*>(action) ? true : false ; if (_actionInstant) { _times -=1 ; } _total = 0 ; return true ; } return false ; } void Repeat::startWithTarget(Node *target){ _total = 0 ; _nextDt = _innerAction->getDuration()/_duration; ActionInterval::startWithTarget(target); _innerAction->startWithTarget(target); }
update
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 void Repeat::update(float dt){ if (dt >= _nextDt) { while (dt > _nextDt && _total < _times) { _innerAction->update(1.0f ); _total++; _innerAction->stop(); _innerAction->startWithTarget(_target); _nextDt += _innerAction->getDuration()/_duration; } if (dt >= 1.0f && _total < _times) { _total++; } if (!_actionInstant) { if (_total == _times) { _innerAction->update(1 ); _innerAction->stop(); } else { _innerAction->update(dt - (_nextDt - _innerAction->getDuration()/_duration)); } } } else { _innerAction->update(fmodf(dt * _times,1.0f )); } }
RepeatForever Spawn 总结