ActionManager动作管理类,在盘古开天之际就被Scheduler撸去变成了一个定时任务。 详见Director::init()

路径

1
2
2d/actions/CCActionManager.h
2d/actions/CCActionManager.cpp

源码分析

其实和Scheduler的实现有些类似 – cocos2dx 3.0 —- Scheduler

tHashElement

1
2
3
4
5
6
7
8
9
10
typedef struct _hashElement
{
struct _ccArray *actions;
Node *target;
int actionIndex;
Action *currentAction;
bool currentActionSalvaged;
bool paused;
UT_hash_handle hh;
} tHashElement;

从结构体上看不出什么特别的,就是类似于Scheduler中的全局定时列表。

mainloop

由于和Scheduler十分类似,这里就直接贴上主循环update函数,其他自行查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void ActionManager::update(float dt)
{
for (tHashElement *elt = _targets; elt != nullptr; ) {
_currentTarget = elt;
_currentTargetSalvaged = false;

if (! _currentTarget->paused) {
/* actions 数组可能在循环中改变 */
for (_currentTarget->actionIndex = 0; _currentTarget->actionIndex < _currentTarget->actions->num;
_currentTarget->actionIndex++) {
_currentTarget->currentAction = (Action*)_currentTarget->actions->arr[_currentTarget->actionIndex];
if (_currentTarget->currentAction == nullptr) {
continue;
}

_currentTarget->currentActionSalvaged = false;

/* 这里是step */
_currentTarget->currentAction->step(dt);

if (_currentTarget->currentActionSalvaged) {
/* 已经被标记为回收状态,则可以调用 release */
_currentTarget->currentAction->release();
} else if (_currentTarget->currentAction->isDone()) {
_currentTarget->currentAction->stop();

Action *action = _currentTarget->currentAction;
/* 将_currentTarget置为空,防止一出action的时候回收 */
_currentTarget->currentAction = nullptr;
removeAction(action);
}

_currentTarget->currentAction = nullptr;
}
}

// elt, at this moment, is still valid
// so it is safe to ask this here (issue #490)
elt = (tHashElement*)(elt->hh.next);

/* 当前对象所有的Action都结束的时候,才把当前对象从hash表中删除 */
if (_currentTargetSalvaged && _currentTarget->actions->num == 0) {
deleteHashElement(_currentTarget);
}
}

// issue #635
_currentTarget = nullptr;
}

step是在Action中的一个虚函数。具体键Action吧 – cocos2dx 3.0 —- Action

总结

ActionManager调用Action的流程:

  1. 在addAction中,先是调用Action::startWithTarget
  2. 在update中每一帧调用step函数,直到Action结束

  1. 在step函数中有可能调用isDone,stop
  2. 在removeAction中只是将Action标记为待回收(currentActionSalvaged = true)