• 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 }
  • 相关阅读:
    软工作业06
    软工作业05
    软工作业00
    软工作业04
    软工作业03
    软工作业02
    我的随笔
    2020软件工程个人作业06——软件工程实践总结作业
    2020软件工程作业05
    软件工程作业00——问题清单
  • 原文地址:https://www.cnblogs.com/deepcho/p/cocos2dx-action-sequence.html
Copyright © 2020-2023  润新知