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; }
发表评论