1. 从一个Action开始
1.1 创建
在Scene里写一个Sprite,并添加Action:
Sprite *sp = Sprite::create("m1.png"); MoveBy *mb = MoveBy::create(20, Vec2(300,10)); sp->runAction(mb); this->addChild(sp);
先通过create方法创建Action,之后Sprite和Action通过runAction方法产生联系。
create方法坐标参数被转为Z为0的三维坐标。
看create方法主要语句:
MoveBy *ret = new (std::nothrow) MoveBy(); ret->initWithDuration(duration, deltaPosition)) ret->autorelease(); return ret;
Action交给内存管理池进行内存管理,还要执行initWithDuration方法。
看initWithDuration方法,调用了父类的ActionInterval的initWithDuration(duration),并设置MoveBy的成员变量:
_positionDelta = deltaPosition; _is3D = true;
看父类的ActionInterval的initWithDuration(duration)方法,是设置了父类成员变量:
_duration = d; _elapsed = 0; _firstTick = true; _done = false;
创建好了Action,执行runAction方法,主要是执行下面的语句:
_actionManager->addAction(action, this, !_running);
ActionManager的addAction方法在我的这篇文章有介绍,再次介绍大致流程:
结束之前执行action的startWithTarget(target)方法,该方法实际执行了其所有继承类的同名方法,对以下成员变量设置:
_originalTarget = _target = aTarget; // Action _elapsed = 0.0f; _firstTick = true; _done = false; _previousPosition = _startPosition = target->getPosition3D(); // MoveBy
简要地说,是把action添加到node对应的element的actions容器中,并通过ActionManager把action和node匹配,并不是“run”。
1.2 运行
Action的实际运行在ActionManager的update方法中,该方法简要地说是对ActionManager的哈希链表_targets进行遍历,对遍历到的每个element的actions再遍历,对遍历到的action执行step(float dt)。
MoveBy的step(float dt)方法实际是执行父类的同名方法,在每次step方法中又会调用一次MoveBy的update方法,step和update的大致流程:
2. 总结
创建并使用action,用到了action的create方法和node的runAction方法,也使action与node产生了关联。
随着ActionManager在每帧调用回调函数update,每个element的action都会执行一次step方法和update方法,step通过已执行的时间(进度时间与帧间隔dt的和)与我们定义的总时长来计算动作执行进度,update把执行进度转为我们在屏幕上看到的进度。当进度到1,动作执行完了,_done置true。