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, pEntry, pTmp)
{
if ((! pEntry->paused) && (! pEntry->markedForDeletion))
{
pEntry->target->update(dt);
}
}
// updates with priority > 0
DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, 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, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
// updates with priority == 0
DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
// updates with priority > 0
DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
m_bUpdateHashLocked = false;
m_pCurrentTarget = NULL;
}