1、创建全局定时器,bool CCDirector::init(void)函数中,调用
// scheduler m_pScheduler = new CCScheduler();
2、在每帧渲染前,都会调用CCScheduler的update方法 // Draw the Scene void CCDirector::drawScene(void) { // calculate "global" dt calculateDeltaTime(); //tick before glClear: issue #533 if (! m_bPaused) //调用定时器的update方法 { m_pScheduler->update(m_fDeltaTime); } }
3、 CCScheduler中有几个很重要的成员变量, //每帧都要调用的定时器 struct _listEntry *m_pUpdatesNegList; // list of priority < 0 //存放priority < 0的Update,优先级最高 struct _listEntry *m_pUpdates0List; // list priority == 0 //存放priority == 0的Update struct _listEntry *m_pUpdatesPosList; // list priority > 0 //存放priority > 0的Update,优先级最低 //方便快速查找 struct _hashUpdateEntry *m_pHashForUpdates; // hash used to fetch quickly the list entries for pause,delete,etc // Used for "selectors with interval",设置了时间间隔的定时器列表 struct _hashSelectorEntry *m_pHashForTimers; //
4、
CCScheduler的update函数很大,主要是几个循环。
// main loop void CCScheduler::update(float dt) { m_bUpdateHashLocked = true; if (m_fTimeScale != 1.0f) { dt *= m_fTimeScale; } // Iterate over all the Updates' selectors tListEntry *pEntry,*pTmp; // updates with priority < 0 优先调用 // pEntry->target->update(dt) 调用target的update方法,例继承与CCNode的类 //可以重写 CCNode的 update方法 /* * Update method will be called automatically every frame if "scheduleUpdate" is called,and the node is "live" */ //virtual void update(float delta); DL_FOREACH_SAFE(m_pUpdatesNegList,pEntry,pTmp) { if ((! pEntry->paused) && (! pEntry->markedForDeletion)) { pEntry->target->update(dt); } } // updates with priority == 0 DL_FOREACH_SAFE(m_pUpdates0List,pTmp) { if ((! pEntry->paused) && (! pEntry->markedForDeletion)) { pEntry->target->update(dt); } } // updates with priority > 0 DL_FOREACH_SAFE(m_pUpdatesPosList,pTmp) { if ((! pEntry->paused) && (! pEntry->markedForDeletion)) { pEntry->target->update(dt); } } // Iterate over all the custom selectors //遍历有时间间隔的定时器列表,调用相应的方法 for (tHashTimerEntry *elt = m_pHashForTimers; elt != NULL; ) { m_pCurrentTarget = elt; m_bCurrentTargetSalvaged = false; if (! m_pCurrentTarget->paused) { // The 'timers' array may change while inside this loop 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); } } // Iterate over all the script callbacks //遍历针对脚本的定时器列表 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); } } } // delete all updates that are marked for deletion // updates with priority < 0 //删除一些没用定时器 DL_FOREACH_SAFE(m_pUpdatesNegList,pTmp) { if (pEntry->markedForDeletion) { this->removeUpdateFromHash(pEntry); } } // updates with priority == 0 DL_FOREACH_SAFE(m_pUpdates0List,pTmp) { if (pEntry->markedForDeletion) { this->removeUpdateFromHash(pEntry); } } // updates with priority > 0 DL_FOREACH_SAFE(m_pUpdatesPosList,pTmp) { if (pEntry->markedForDeletion) { this->removeUpdateFromHash(pEntry); } } m_bUpdateHashLocked = false; m_pCurrentTarget = NULL; }