好记性不如铅笔头

C && C++, cocos2dx, 编程

cocos2dx学习笔记:CCActionManager

CCActionManager用来管理所有的action。这里简单的备注下CCActionManager的框架代码,CCActionManager的代码很清晰明了,需要注意的是一个比较特殊的情况,即:执行的action的业务逻辑为 删除自己或者删除其他的action,个人感觉主要是CCCallFunc*的引入导致的,CCCallFunc*的函数可以调用CCActionManager的函数来删除action

CONTENTS

CCNode添加action:

//各种action其实是通过CCActionManager管理的。
CCAction * CCNode::runAction(CCAction* action)
{
    CCAssert( action != NULL, "Argument must be non-nil");
    m_pActionManager->addAction(action, this, !m_bRunning);
    return action;
}

CCDirector相关代码:

//在CCDirector的初始化中,初始化了CCActionManager,而且定时了它的update方法。
bool CCDirector::init(void)
{
。。。。。
。。。。。
    // action manager
    m_pActionManager = new CCActionManager();
    m_pScheduler->scheduleUpdateForTarget(m_pActionManager, kCCPrioritySystem, false);
。。。。。
。。。。。
}

CCActionManager部分代码:

void CCActionManager::addAction(CCAction *pAction, CCNode *pTarget, bool paused)
{
    CCAssert(pAction != NULL, "");
    CCAssert(pTarget != NULL, "");


//先寻找当前hash表中有没有这个target,如果没有,新建一个tHashElement,然后将其加入hash表
    tHashElement *pElement = NULL;
    // we should convert it to CCObject*, because we save it as CCObject*
    CCObject *tmp = pTarget;
    HASH_FIND_INT(m_pTargets, &tmp, pElement);
    if (! pElement)
    {
        pElement = (tHashElement*)calloc(sizeof(*pElement), 1);
        pElement->paused = paused;
        pTarget->retain();
        pElement->target = pTarget;
        HASH_ADD_INT(m_pTargets, target, pElement);
    }

//保证这个tHashElement有空闲的数组元素
     actionAllocWithHashElement(pElement);
 
//将这个action放到数组中
     CCAssert(! ccArrayContainsObject(pElement->actions, pAction), "");
     ccArrayAppendObject(pElement->actions, pAction);
 
//开始action
     pAction->startWithTarget(pTarget);
}


//删除某个target的所有action
void CCActionManager::removeAllActionsFromTarget(CCObject *pTarget)
{
    // explicit null handling
    if (pTarget == NULL)
    {
        return;
    }

    tHashElement *pElement = NULL;
    HASH_FIND_INT(m_pTargets, &pTarget, pElement);
		//根据target找到相应的hashelement
    if (pElement)
    {
    		//如果当前正在执行的action属于这个target,那么就不能释放这个action,在该action执行完毕后释放该action。
    		//出现该处逻辑是因为action里可能会包含删除其他action或者删除自己的逻辑,如果是这样,那么调用到该处代码的
    		//逻辑为当前执行的action的逻辑是清空所有action,为了防止不必要的问题,这里先标记这个正在执行的action,释放掉其他的actin,
    		//在执行完该action后释放它。参考update函数
        if (ccArrayContainsObject(pElement->actions, pElement->currentAction) && (! pElement->currentActionSalvaged))
        {
            pElement->currentAction->retain();
            pElement->currentActionSalvaged = true;
        }

        ccArrayRemoveAllObjects(pElement->actions);
        
        //同上分析,如果当前正在执行的action所属的target正是本target,那么先标记,延后释放。
        if (m_pCurrentTarget == pElement)
        {
            m_bCurrentTargetSalvaged = true;
        }
        else
        {
            deleteHashElement(pElement);
        }
    }
    else
    {
//        CCLOG("cocos2d: removeAllActionsFromTarget: Target not found");
    }
}



void CCActionManager::update(float dt)
{
    for (tHashElement *elt = m_pTargets; elt != NULL; )
    {
    //记录下正在执行的target,
        m_pCurrentTarget = elt;
        m_bCurrentTargetSalvaged = false;

        if (! m_pCurrentTarget->paused)
        {
            // The 'actions' CCMutableArray may change while inside this loop.
            for (m_pCurrentTarget->actionIndex = 0; m_pCurrentTarget->actionIndex < m_pCurrentTarget->actions->num;
                m_pCurrentTarget->actionIndex++)
            {
                //记录下正在执行的action
                m_pCurrentTarget->currentAction = (CCAction*)m_pCurrentTarget->actions->arr[m_pCurrentTarget->actionIndex];
                if (m_pCurrentTarget->currentAction == NULL)
                {
                    continue;
                }

                m_pCurrentTarget->currentActionSalvaged = false;

                m_pCurrentTarget->currentAction->step(dt);
								
								//如果action执行之后,标志位被标记,说明这个action的业务是删除自己或者删除所有,这里action的逻辑已经执行完了,
								//在这个地方安全的把自己删掉。
                if (m_pCurrentTarget->currentActionSalvaged)
                {
                    // 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.
                    m_pCurrentTarget->currentAction->release();
                } else
                if (m_pCurrentTarget->currentAction->isDone())
                {
                    m_pCurrentTarget->currentAction->stop();

                    CCAction *pAction = m_pCurrentTarget->currentAction;
                    // Make currentAction nil to prevent removeAction from salvaging it.
                    m_pCurrentTarget->currentAction = NULL;
                    removeAction(pAction);
                }

                m_pCurrentTarget->currentAction = NULL;
            }
        }

        // elt, at this moment, is still valid
        // so it is safe to ask this here (issue #490)
        elt = (tHashElement*)(elt->hh.next);
        
        //同上分析,如果target的action里包含删除自己,或者target的所有的action全部都执行完了,就将该target从hash表中删掉。
        // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
        if (m_bCurrentTargetSalvaged && m_pCurrentTarget->actions->num == 0)
        {
            deleteHashElement(m_pCurrentTarget);
        }
    }

    // issue #635
    m_pCurrentTarget = NULL;
}

 

发表评论

16 − 14 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据