上篇文章是关于Action的工作流程和ActionManager的执行原理,本文说说Action的分类和具体的设计
动作类型的分类:
一、限时动作:FiniteTimeAction
包括:即时动作(CCActionInstance)和持续时间动作(CCActionInterval)1、即时动作:即时动作有几个其实是只改变的node的position,visible等属性而已,例如CCPlace,CCShow等,这些主要是把他们包装成动作后可以方便的与其他动作类组合为复杂动作
其次还有CCCallFunc和CCRemoveSelf,前者一般用于动作回调,后者一般用于在执行动作组合的最后移除目标节点
CallFunc:void CallFunc::execute() {
if (_callFunc) {
(_selectorTarget->*_callFunc)();
} else if( _function ){
_function();
}
}
CallFuncN:void CallFuncN::execute() {
if (_callFuncN) {
(_selectorTarget->*_callFuncN)(_target);
}
else if (_functionN) {
_functionN(_target);
}
}
CCCallFuncND:void __CCCallFuncND::execute()
{
if (_callFuncND)
{
(_selectorTarget->*_callFuncND)(_target, _data);
}
}
CCCallFuncO:void __CCCallFuncO::execute()
{
if (_callFuncO) {
(_selectorTarget->*_callFuncO)(_object);
}
}
RemoveSelf:void RemoveSelf::update(float time) {
CC_UNUSED_PARAM(time);
_target->removeFromParentAndCleanup(_isNeedCleanUp);
}
2、持续时间动作:一般项目中用的最多的是持续时间动作,包括熟悉的CCMoveTo,CCMoveBy...根据时间的长度,平均分为n段在每帧执行
逆动作(reverse):并非所有动作都有逆动作,一般XXBy这种设置属性为相对值的动作才存在逆动作,而XXXTo的动作一般没有逆动作MoveBy* MoveBy::reverse() const
{
return MoveBy::create(_duration, Vec2( -_positionDelta.x, -_positionDelta.y));
}
为什么XXXTo类的动作不会有reverse动作:
因为如果XXXTo类的动作在如果要创建逆动作的时候,需要获取目标节点的初始属性,而初始属性的获取是在Node:runAction的时候
才会获取的,但是动作在创建的时候,并没有关联到Node上,所以不可以获取逆动作。
获取初识属性:void MoveTo::startWithTarget(Node *target)
{
MoveBy::startWithTarget(target);
_positionDelta = _endPosition - target->getPosition();
}
//该函数在ActionManager中的addAction中调用,当runAction的时候才获取节点属性
持续时间动作的分类:
位置变化动作:Move,Jump,Bezier
属性变化动作:Scale,Rotate,Fade,Tint
视觉特效动作:Blink,Animation
控制动作:DelayTime,Repeat,RepeatForever二、变速动作:Speed(包装一个持续时间的动作,改变该动作的速度,可以为负数)Speed* Speed::create(ActionInterval* action, float speed)
{
Speed *ret = new (std::nothrow) Speed();
if (ret && ret->initWithAction(action, speed))
{
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
void Speed::step(float dt)
{
_innerAction->step(dt * _speed);
}
CCActionEase:更加灵活的变速运动,基类是ActionInterval,同样包装了一个持续性的动作,只是在update的时候,将匀速变为加速(通过公式计算)void EaseIn::update(float time)
{
_inner->update(tweenfunc::easeIn(time, _rate));
}
其中串行和并行的动作组CCSequence和CCSpawn是靠createWithTwoActions递归而成的。update的时候其实也是一个递归的过程Spawn* Spawn::create(const Vector& arrayOfActions)
{
Spawn* ret = nullptr;
do
{
auto count = arrayOfActions.size();
CC_BREAK_IF(count == 0);
auto prev = arrayOfActions.at(0);
if (count > 1)
{
for (int i = 1; i < arrayOfActions.size(); ++i)
{
prev = createWithTwoActions(prev, arrayOfActions.at(i));
}
}
else
{
// If only one action is added to Spawn, make up a Spawn by adding a simplest finite time action.
prev = createWithTwoActions(prev, ExtraAction::create());
}
ret = static_cast(prev);
}while (0);
return ret;
}*>*>