cocos2dx源码分析:ActionManager

当我们调用runAction的时候,实际上是创建一个Action,并把这个Action交给ActionManager管理,由ActionManager负责更新Action的行为和管理Action的生命周期。

Director在初始化的时候会创建一个ActionManager

_actionManager = new (std::nothrow) ActionManager();
_scheduler->scheduleUpdate(_actionManager, Scheduler::PRIORITY_SYSTEM, false);

Node对象在构造的时候,会在自己的成员变量里面保存一个Director的ActionManager的指针

_director = Director::getInstance();
_actionManager = _director->getActionManager();
_actionManager->retain();

当我们调用runAction的时候,就会把action交给ActionManager管理

Action * Node::runAction(Action* action)
{
    CCASSERT( action != nullptr, "Argument must be non-nil");
    _actionManager->addAction(action, this, !_running);
    return action;
}
void ActionManager::addAction(Action *action, Node *target, bool paused)
{
    CCASSERT(action != nullptr, "action can't be nullptr!");
    CCASSERT(target != nullptr, "target can't be nullptr!");
    /*找到target相关的成员*/
    tHashElement *element = nullptr;
    // we should convert it to Ref*, because we save it as Ref*
    Ref *tmp = target;
    HASH_FIND_PTR(_targets, &tmp, element);
    if (! element)
    {
        /*没有找到就创建一个*/
        element = (tHashElement*)calloc(sizeof(*element), 1);
        element->paused = paused;
        target->retain();
        element->target = target;
        HASH_ADD_PTR(_targets, target, element);
    }
    /*扩展可以容纳的action数量*/
     actionAllocWithHashElement(element);

     CCASSERT(! ccArrayContainsObject(element->actions, action), "action already be added!");
     /*存入新action*/
     ccArrayAppendObject(element->actions, action);

     action->startWithTarget(target);
}

ActionManager创建的时候,把自己的update函数加入了scheduler,所有ActionManager::update每贞都会被调用,用来更新管理的action行为

_scheduler->scheduleUpdate(_actionManager, Scheduler::PRIORITY_SYSTEM, false);
void ActionManager::update(float dt)
{
    /*遍历所有的action管理成员,每个node对应一个管理成员,管理node的所有action*/
    for (tHashElement *elt = _targets; elt != nullptr; )
    {
        _currentTarget = elt;
        _currentTargetSalvaged = false;
        /*如果目标是暂停状态可以不处理*/
        if (! _currentTarget->paused)
        {
            // The 'actions' MutableArray may change while inside this loop.
            /*遍历所有的action*/
            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;
                /*更新action的行为*/
                _currentTarget->currentAction->step(dt);

                if (_currentTarget->currentActionSalvaged)
                {
                    /*处理执行action的时候,action被删除的情况*/
                    // The currentAction told the node to remove it. To prevent the action from
                    // accidentally deallocating itself before finishing its step, we retained
                    // it. Now that step is done, it's safe to release it.
                    _currentTarget->currentAction->release();
                } else
                if (_currentTarget->currentAction->isDone())
                {
                    /*如果action已完成则删除这个action*/
                    _currentTarget->currentAction->stop();

                    Action *action = _currentTarget->currentAction;
                    // Make currentAction nil to prevent removeAction from salvaging it.
                    _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);

        // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
        /*如果目标节点已经没有action了,则可以删除这个管理元素,释放内存资源*/
        if (_currentTargetSalvaged && _currentTarget->actions->num == 0)
        {
            deleteHashElement(_currentTarget);
        }
    }

    // issue #635
    _currentTarget = nullptr;
}

你可能感兴趣的:(cocos2d-x)