在Cocos2d-x 3.3中ActionInterval主要负责记录持续动作已执行了多长时间。它对应于ActionInstant(瞬时动作),ActionInterval的继承关系如下图所示:
其下还继承了很多的持续动作类,这里只截取了一部分。
1、成员变量:
protected:
float _elapsed; // 动作已执行了多长时间。
/* 这个是为了防jerk而设定的,不过jerk是什么我还不是特别清楚,图像抖动吗?
* 下面说到step()成员方法的源码实现时还会说到。
*/
bool _firstTick;
2、成员方法:
(1) inline float getElapsed(void) { return _elapsed; }
该方法用于获得从动作开始执行后过去了多少秒。
(2) void setAmplitudeRate(float amp);
float getAmplitudeRate(void);
这两个方法用于设置格子动画的振幅,不过好像还没有实现。
(3) virtual bool isDone(void) const override;
该方法用于判断动作是否执行完毕。
实现源码:
bool ActionInterval::isDone() const
{
return _elapsed >= _duration;
}
很简单,当发现动作的执行时间大于等于指定的时间,则说明动作已经执行完成。
(4) bool initWithDuration(float d);
该函数用于初始化动作的持续时间(_duration)以及动作已执行的时间(_elapsed)。
d:动作持续时间。
实例:
该函数不需要应用程序中主动调用,一般由ActionInterval的派生类调用create()时内部调用,例如MoveBy::create()。
实现源码:
bool ActionInterval::initWithDuration(float d)
{
_duration = d; // 初始化动作的持续时间,_duration属于ActionInterval的父类。
// prevent division by 0
// This comparison could be in step:, but it might decrease the performance
// by 3% in heavy based action games.
if (_duration == 0)
{
/* 这里是为了防止_duration作为除数时其被设置为0。
* FLT_EPSILON是一个计算机所能识别的最小正数。
* _duration我看到的只在ActionInterval::step()中作为除数,
* 但那里有个MAX(_duration, FLT_EPSILON)作为保障机制,
* 所以我理解这里不用特别将_duration = FLT_EPSILON亦可。
* 对上面注释的理解,是否是说由于影响游戏的性能,
* step()中可以不用MAX()对_duration的值进行保障,而放在这里?
*/
_duration = FLT_EPSILON;
}
_elapsed = 0; // 初始化动作已持续时间。
_firstTick = true; // 为了防止jerk而设置的变量。
return true;
}
关键点总结:
该函数要结合ActionInterval派生类的create()来看,比如MoveBy::create()。
对于_duration作为除数需要非零的保障,在ActionInterval::step()中使用MAX()或者在ActionInterval::initWithDuration()中直接赋值均可。考虑到在游戏运行过程中step()会被经常调用,在step()中总去MAX()会影响游戏的性能,所以可在initWithDuration()将_duration赋值好,step()中直接使用即可。
(5) virtual void startWithTarget(Node *target) override;
该函数用于将动作与精灵进行绑定。
target:待执行动作的精灵。
实例:
该函数不需要应用程序中主动调用,一般由精灵调用runAction()关联动作时内部调用,例如mySprite->runAction(myRotateBy);。
实现源码:
void ActionInterval::startWithTarget(Node *target)
{
FiniteTimeAction::startWithTarget(target); // 其父类将精灵与动作进行绑定。
_elapsed = 0.0f; // 初始化动作已持续时间。
_firstTick = true; // 防止jerk而设置的变量。
}
关键点总结:
该函数要结合精灵的runAction()来看,比如mySprite->runAction(myRotateBy)。
(6) virtual void step(float dt) override;
该函数根据流逝的时间计算出动作的进度(百分比形式),然后将这个进度传递给动作的update()进行更新。
dt:从上一帧到这一帧所流逝的时间。
实例:
无。
实现源码:
void ActionInterval::step(float dt)
{
if (_firstTick) // 防止jerk,step()第一次被调用时会进入这里。
{
_firstTick = false;
_elapsed = 0;
}
else
{
_elapsed += dt; // _elapsed存储动作已执行的时间。
}
/* 首先使用MAX()保障_duration非0;之后用动作已执行时间除以动作总的持续时间
* 得到动作已完成的进度(理解为百分比)。当动作的进度为1的时候相当于100%,
* 这里使用MIN()保障动作的执行进度不会超过100%。
* 最后一个MAX()不是很理解,难道进度会有负值的情况?
*/
this->update(MAX (0, // needed for rewind. elapsed could be negative
MIN(1, _elapsed /
MAX(_duration, FLT_EPSILON) // division by 0
)
)
);
}
关键点总结:
该函数由引擎内部调用,当动作执行起来后不停的被调用。函数中首先累计动作已执行时间,之后根据这个时间以及动作的总持续时间,算出当前动作的执行进度,最后将进度交给update()更新精灵的状态。
函数中最后update()参数中的最后一个MAX()不太理解,难道进度会有负数的情况?
(7) virtual ActionInterval* reverse() const override
virtual ActionInterval *clone() const override
这两个函数在ActionInterval中不能被调用,需要其派生来实现。