[Cocos2d-x for WP8学习笔记] mainloop中的update方法分析

Posted by baicai on July 15, 2013
void CCScheduler::update(float dt)
{
    m_bUpdateHashLocked = true;

 // 预处理
    if (m_fTimeScale != 1.0f)
    {
        dt *= m_fTimeScale;
    }

    // 枚举所有的update定时器
    tListEntry *pEntry, *pTmp;

    CCScriptEngineProtocol* pEngine = CCScriptEngineManager::sharedManager()->getScriptEngine();

    // 优先级小于0的定时器
    DL_FOREACH_SAFE(m_pUpdatesNegList, pEntry, pTmp)
    {
        if ((! pEntry->paused) && (! pEntry->markedForDeletion))
        {
            if (pEngine != NULL && kScriptTypeJavascript == pEngine->getScriptType())
            {
                pEngine->executeSchedule(0, dt, (CCNode *)pEntry->target);
            }

            pEntry->target->update(dt);
        }
    }

    // 优先级等于0的定时器
    DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
    {
        if ((! pEntry->paused) && (! pEntry->markedForDeletion))
        {
            if (pEngine != NULL && kScriptTypeJavascript == pEngine->getScriptType())
            {
                pEngine->executeSchedule(0, dt, (CCNode *)pEntry->target);
            }
            
            pEntry->target->update(dt);
        }
    }

    // 优先级大于0的定时器
    DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
    {
        if ((! pEntry->paused) && (! pEntry->markedForDeletion))
        {
            if (pEngine != NULL && kScriptTypeJavascript == pEngine->getScriptType())
            {
                pEngine->executeSchedule(0, dt, (CCNode *)pEntry->target);
            }

            pEntry->target->update(dt);
        }
    }

    // 枚举所有的普通定时器
    for (tHashTimerEntry *elt = m_pHashForTimers; elt != NULL; )
    {
        m_pCurrentTarget = elt;
        m_bCurrentTargetSalvaged = false;

        if (! m_pCurrentTarget->paused)
        {
   //枚举此节点中的计时器
            // timers数组可能在循环中改变  需要格外小心
            for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
            {
                elt->currentTimer = (CCTimer*)(elt->timers->arr[elt->timerIndex]);
                elt->currentTimerSalvaged = false;

                elt->currentTimer->update(dt);

                if (elt->currentTimerSalvaged)
                {
                    // The currentTimer told the remove itself. To prevent the timer from
                    // accidentally deallocating itself before finishing its step, we retained
                    // it. Now that step is done, it's safe to release it.
                    elt->currentTimer->release();
                }

                elt->currentTimer = NULL;
            }
        }

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

        // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
        if (m_bCurrentTargetSalvaged && m_pCurrentTarget->timers->num == 0)
        {
            removeHashElement(m_pCurrentTarget);
        }
    }

    // 处理脚本引擎的相关事宜
    if (m_pScriptHandlerEntries)
    {
        for (int i = m_pScriptHandlerEntries->count() - 1; i >= 0; i--)
        {
            CCSchedulerScriptHandlerEntry* pEntry = static_cast<CCSchedulerScriptHandlerEntry*>(m_pScriptHandlerEntries->objectAtIndex(i));
            if (pEntry->isMarkedForDeletion())
            {
                m_pScriptHandlerEntries->removeObjectAtIndex(i);
            }
            else if (!pEntry->isPaused())
            {
                pEntry->getTimer()->update(dt);
            }
        }
    }

    // 清理所有的被标记了删除记号的update方法
    // 优先级小于0的定时器
    DL_FOREACH_SAFE(m_pUpdatesNegList, pEntry, pTmp)
    {
        if (pEntry->markedForDeletion)
        {
            this->removeUpdateFromHash(pEntry);
        }
    }

    // 优先级等于0的定时器
    DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
    {
        if (pEntry->markedForDeletion)
        {
            this->removeUpdateFromHash(pEntry);
        }
    }

    // 优先级大于0的定时器
    DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
    {
        if (pEntry->markedForDeletion)
        {
            this->removeUpdateFromHash(pEntry);
        }
    }

    m_bUpdateHashLocked = false;

    m_pCurrentTarget = NULL;
}