cocos2d-x v3.3 FiniteTimeAction and Action

FiniteTimeAction主要负责记录动作的持续时间,而Action主要负责存储执行动作者的相关信息,它们的继承关系如下:

ActionInstant和ActionInterval均是FiniteTimeAction的派生类。这也体现了它抽象的概念,ActionInterval类的动作的持续时间在它这里存储,ActionInterval类的动作的持续时间理解为0就好了。

FiniteTimeAction:

1、成员变量:

protected:
float _duration; // 动作的持续时间。

private:
CC_DISALLOW_COPY_AND_ASSIGN(FiniteTimeAction); // 禁用拷贝构造函数和拷贝赋值操作符。

2、成员方法:

(1) inline float getDuration() const { return _duration; }
inline void setDuration(float duration) { _duration = duration; }

这两个方法分别用于获得和设置动作的持续时间,很简单,就是在操作_duration成员变量。

(2) virtual FiniteTimeAction* reverse() const override
virtual FiniteTimeAction* clone() const override

这两个函数在FiniteTimeAction中不能被调用,同样在其子类ActionInstant和ActionInterval中也没有被实现,需要最终具体的动作类来实现,例如MoveBy,MoveTo等。

关键点总结:

♂ FiniteTimeAction就这么多东西,是不是很简单,它就是用来管理动作的持续时间而存在的。

Action:

1、成员变量:

public:
static const int INVALID_TAG = -1; // 代表无效的标签(_tag的初始值)。
protected:
/* 原始的动作执行者。

 * 这里我理解的,ActionManager具体管理动作的执行,当发现动作执行完毕后,
 * ActionManager调用Action::stop()结束动作,接着调用自己的removeAction()做收尾工作。
 * 而Action::stop()一旦被调用后,Action::_target会被置空。那么ActionManager如何找到动作执行者呢?这就需要通过_originalTarget来获得。
 * 所以这个成员变量不是由于执行动作的精灵会改变而存储最初执行动作的精灵而存在,而是为了方便ActionManager做收尾工作而使用的。
 */
Node    *_originalTarget;
Node    *_target;    // 动作执行者。对比上面的_originalTarget看。

这句注释我不太明白:The target is ‘assigned’, it is not ‘retained’. 谁能给我解释解释。★_★
/* 动作的标签。
* 在一个函数中创建了一个动作,在函数可以通过变量名来控制它,那出了这个函数之后还想控制它怎么办?
* 这时就可以在函数中创建动作后给它“贴一个标签”,之后在函数外就可以通过标签访问动作了。
* 举例:ActionManager::getActionByTag()就可以通过tag来寻找Action。
*/
int _tag;
private:
CC_DISALLOW_COPY_AND_ASSIGN(Action); // 禁用拷贝构造函数和拷贝赋值操作符。

2、成员方法:

(1) virtual std::string description() const

该方法用于获取动作的相关信息。目前其内部实现只组织了动作的tag值进行返回。

实现源码:

std::string Action::description() const
{   
    return StringUtils::format("<Action | Tag = %d", _tag);    // 使用有些类似printf()的感觉。
}   

(2) virtual Action* clone() const
virtual Action* reverse() const

这两个方法与上面FiniteTimeAction中对应的两个方法一样,不在本类中实现,应由最终的动作类实现。

(3) virtual bool isDone() const

该方法用于判断动作是否执行完毕。在本类中的实现始终返回true,具体的使用在其孙子类中实现了(ActionInterval和ActionInstant)。

实现源码:

bool Action::isDone() const
{   
    return true;
}

(4) virtual void startWithTarget(Node *target)

该方法用于记录动作执行者。

target:动作执行者。

实例:

mySprite->runAction(MoveBy::create(1, 100));

上面的语句,由runAction()触发,MoveBy::startWithTarget() --> ActionInterval::startWithTarget() --> Action::startWithTarget()。

实现源码:

void Action::startWithTarget(Node *aTarget)
{    
    _originalTarget = _target = aTarget;    // 原始的动作执行者和动作执行者均初始化为当前动作的执行者。
}

关键点总结:

♂ _originalTarget在“精灵->runAction()”的过程中初始化,之后的值不会改变,只是供ActionManager使用。

(5) virtual void stop()

该方法用于将动作停止。

实现源码:

void Action::stop()
{
    _target = nullptr;    // 相当简单,将动作执行者置为NULL。
}

关键点总结:

♂ ActionManager管理所有动作的执行,引擎在每一帧都会触发ActionManager::update(),其中它会通过调用Action::isDone()来判断该动作是否执行完成,如果执行完成则会调用Action::stop()停止动作。之后还会调用ActionManager::removeAction()做收尾工作,这些还会在ActionManager的分析中提及。

(6) virtual void step(float dt)
virtual void update(float time)

这两个方法配套使用,用于在动作执行过程中不断的更新动作的状态。
这两个方法在本类中没有实现实质的内容。对于ActionInterval类的动作,在ActionInterval中实现step,在最终的动作类中实现update;对于ActionInstant类的动作,由于是一次性执行完成,没有持续时间的概念,也就不需要多次的更新。所以在ActionInstant中实现了step和update,不过均没有实质性的内容。

实现源码:

void Action::step(float dt)
{
    CC_UNUSED_PARAM(dt);
    CCLOG(". override me");
}

void Action::update(float time)
{
    CC_UNUSED_PARAM(time);
    CCLOG(". override me");
}

(7) inline Node* getTarget() const { return _target; }
inline void setTarget(Node target) { _target = target; }
inline Node
getOriginalTarget() const { return _originalTarget; }
inline void setOriginalTarget(Node *originalTarget) { _originalTarget = originalTarget; }
inline int getTag() const { return _tag; }
inline void setTag(int tag) { _tag = tag; }

这些方法都是直接操作成员变量的,一看就明白。★_★