#ifndef __CCSCHEDULER_H__
#define __CCSCHEDULER_H__
#include "cocoa/CCObject.h"
#include "support/data_support/uthash.h"
NS_CC_BEGIN
// Priority level reserved for system services.
#define kCCPrioritySystem INT_MIN //#define INT_MIN (-2147483647 - 1)
// Minimum priority level for user scheduling.
#define kCCPriorityNonSystemMin (kCCPrioritySystem+1)
class CCSet;//要用到CCSet类进行存储
//
// CCTimer
//
/** @brief Light-weight timer */ //轻量级定时器 调用间隔时间固定不变,一旦设置不在管控
//
class CC_DLL CCTimer : public CCObject
{
public:
CCTimer(void);
float getInterval(void) const;
void setInterval(float fInterval);
SEL_SCHEDULE getSelector() const; //SEL_SCHEDULE = 函数指针类型 具体-> cocos2dx/选择器详细
bool initWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector); //使用一个 selector(回调函数) 、 一个 target 初始化一个定时器
// 初始化一个定时器:1、target 2、 selector 3、时间间隔(以秒为单位)4、重复次数 5、延迟几秒钟后执行 .
bool initWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector, float fSeconds, unsigned int nRepeat, float fDelay);
/** Initializes a timer with a script callback function and an interval in seconds. */
bool initWithScriptHandler(int nHandler, float fSeconds); //1、脚本回调函数 2、一个时间间隔(以秒为单位)
/** triggers(触发 引爆) the timer */
void update(float dt);
{
if (m_fElapsed == -1)
{
m_fElapsed = 0;
m_uTimesExecuted = 0;
}
else
{
if (m_bRunForever && !m_bUseDelay)
{//standard timer usage
m_fElapsed += dt;
if (m_fElapsed >= m_fInterval)
{
if (m_pTarget && m_pfnSelector)
{
(m_pTarget->*m_pfnSelector)(m_fElapsed);
}
{
CCScriptEngineManager::sharedManager()->getScriptEngine()->executeSchedule(m_nScriptHandler, m_fElapsed);
}
m_fElapsed = 0;
}
}
else
{//advanced usage
m_fElapsed += dt;
if (m_bUseDelay)
{
if( m_fElapsed >= m_fDelay )
{
if (m_pTarget && m_pfnSelector)
{
(m_pTarget->*m_pfnSelector)(m_fElapsed);
}
{
CCScriptEngineManager::sharedManager()->getScriptEngine()->executeSchedule(m_nScriptHandler, m_fElapsed);
}
m_uTimesExecuted += 1;
m_bUseDelay = false;
}
}
else
{
if (m_fElapsed >= m_fInterval)
{
if (m_pTarget && m_pfnSelector)
{
(m_pTarget->*m_pfnSelector)(m_fElapsed);
}
{
CCScriptEngineManager::sharedManager()->getScriptEngine()->executeSchedule(m_nScriptHandler, m_fElapsed);
}
m_uTimesExecuted += 1;
}
{ //unschedule timer
CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(m_pfnSelector, m_pTarget);
}
}
}
}
public:
/** Allocates(分配) a timer with a target and a selector. */
static CCTimer* timerWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector); //创建定时器
/** Allocates a timer with a target, a selector and an interval in seconds. */
static CCTimer* timerWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector, float fSeconds); //创建定时器
/** Allocates a timer with a script callback function and an interval in seconds. */
static CCTimer* timerWithScriptHandler(int nHandler, float fSeconds); //创建定时器 1、脚本回调函数 2、一个时间间隔(以秒为单位)
inline int getScriptHandler() { return m_nScriptHandler; }; //
protected:
CCObject *m_pTarget;
float m_fElapsed;
bool m_bRunForever;
bool m_bUseDelay;
unsigned int m_uTimesExecuted;
unsigned int m_uRepeat; //0 = once, 1 is 2 x executed
float m_fDelay;
float m_fInterval;
SEL_SCHEDULE m_pfnSelector; // 一个参数是float 返回void的函数指针
int m_nScriptHandler;
};
~~~~~~~~
struct _listEntry;
struct _hashSelectorEntry;
struct _hashUpdateEntry;
// c的结构体写法 不要学! c++的结构体更方便
struct _listEntry *prev, *next;
CCObject *target; // not retained (retained by hashUpdateEntry)
int priority;
bool paused;
bool markedForDeletion; // selector will no longer be called and entry will be removed at end of the next tick
} tListEntry;
{
tListEntry **list; // Which list does it belong to ? “事件”属于哪一个“事件”链表
tListEntry *entry; // entry in the list “事件”节点
CCObject *target; // hash key (retained) “事件”在hash中得key 用target指针表示
UT_hash_handle hh;
} tHashUpdateEntry;
typedef struct _hashSelectorEntry //timer(轻型计时器)节点 第一个成员表示节点属于哪一个timer 链表
{
ccArray *timers; //节点属于哪一个timer 链表
CCObject *target; // hash key (retained)
unsigned int timerIndex;
CCTimer *currentTimer; //当前执行的timer
bool currentTimerSalvaged;
bool paused;
UT_hash_handle hh;
} tHashTimerEntry;
/
class CCArray;
//
There are 2 different types of callbacks (selectors):
- update selector: the 'update' selector will be called every frame. You can customize the priority.
- custom selector: A custom selector will be called every frame, or with a custom interval of time
//
class CC_DLL CCScheduler : public CCObject //schedule 安排 计划 ,调度器
{
public:
CCScheduler();
~CCScheduler(void);
//得到 设置时间精度
inline float getTimeScale(void) { return m_fTimeScale; } //得到时间精度 默认1 >1快动作 <1慢动作
inline void setTimeScale(float fTimeScale) { m_fTimeScale = fTimeScale; } //设置时间精度 <1时慢动作 >1时快进
//更新scheduler.
voidupdate(float dt);
{
m_bUpdateHashLocked = true;
{
dt *= m_fTimeScale;
}
tListEntry *pEntry, *pTmp;
DL_FOREACH_SAFE( m_pUpdatesNegList , pEntry, pTmp) //遍历
{
if ((! pEntry->paused) && (! pEntry->markedForDeletion))
{
pEntry->target->update(dt);
}
}
DL_FOREACH_SAFE( m_pUpdates0List , pEntry, pTmp)
{
if ((! pEntry->paused) && (! pEntry->markedForDeletion))
{
pEntry->target->update(dt);
}
}
DL_FOREACH_SAFE( m_pUpdatesPosList , pEntry, pTmp)
{
if ((! pEntry->paused) && (! pEntry->markedForDeletion))
{
pEntry->target->update(dt);
}
}
for (tHashTimerEntry *elt = m_pHashForTimers; elt != NULL; ) //遍历
{
m_pCurrentTarget = elt;
m_bCurrentTargetSalvaged = false;
{
// 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;
{
// 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();
}
}
}
// so it is safe to ask this here (issue #490)
elt = (tHashTimerEntry *)elt->hh.next;
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);
}
}
}
// updates with priority < 0
DL_FOREACH_SAFE(m_pUpdatesNegList, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
}
// 前5个参数用于create 一个 CCTimer变量 这个timer用于初始化 一个tHashTimerEntry节点 最终add到 this->m_pHashForTimers
void scheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget, float fInterval, unsigned int repeat, float delay, bool bPaused);
{
CCAssert(pfnSelector, "Argument selector must be non-NULL");
CCAssert(pTarget, "Argument target must be non-NULL");
HASH_FIND_INT(m_pHashForTimers, &pTarget, pElement); //哈希表m_pHashForTimers中根据键pTarget查找 tHashTimerEntry 找到后赋给pElement
{
pElement = (tHashTimerEntry *)calloc(sizeof(*pElement), 1);
pElement->target = pTarget;
if (pTarget)
{
pTarget->retain();
}
HASH_ADD_INT(m_pHashForTimers, target, pElement); //add tHashTimerEntry节点
}
else
{
CCAssert(pElement->paused == bPaused, "");
}
{
pElement->timers = ccArrayNew(10);
}
else
{
for (unsigned int i = 0; i < pElement->timers->num; ++i)
{
CCTimer *timer = (CCTimer*)pElement->timers->arr[i];
{
CCLOG("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer->getInterval(), fInterval);
timer->setInterval(fInterval);
return;
}
}
ccArrayEnsureExtraCapacity(pElement->timers, 1);
}
pTimer->initWithTarget(pTarget, pfnSelector, fInterval, repeat, delay);
ccArrayAppendObject(pElement->timers, pTimer); //用ptimer赋值pElement->timers
pTimer->release();
}
// kRepeatForever 、 0 延迟 ,内部调用 scheduleSelector
void scheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget, float fInterval, bool bPaused);
/** Schedules the 'update' selector for a given target with a given priority.将update加入时间进度表需要 target ,priority
The 'update' selector will be called every frame. The 'update' selector 他每一帧都会被调用
The lower the priority, the earlier it is called.priority(优先级) 越低越早调用.
*/
voidscheduleUpdateForTarget(CCObject *pTarget, int nPriority, bool bPaused);
void CCScheduler::scheduleUpdateForTarget(CCObject *pTarget, int nPriority, bool bPaused)
{
tHashUpdateEntry *pHashElement = NULL;
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pHashElement);
if (pHashElement)
{
#if COCOS2D_DEBUG >= 1
CCAssert(pHashElement->entry->markedForDeletion,"");
#endif
// TODO: check if priority has changed!
pHashElement->entry->markedForDeletion = false;
return;
}
// most of the updates are going to be 0, that's way there
// is an special list for updates with priority 0
if (nPriority == 0)
{
appendIn(&m_pUpdates0List, pTarget, bPaused);// 加入m_pUpdates0List
}
else if (nPriority < 0)
{
priorityIn(&m_pUpdatesNegList, pTarget, nPriority, bPaused);// 加入m_pUpdatesNegList
}
else
{
// priority > 0
priorityIn(&m_pUpdatesPosList, pTarget, nPriority, bPaused);// 加入m_pUpdatesPosList
}
}
/** Unschedule a selector for a given target.取消给定的 target 对应的 selectort
If you want to unschedule the "update", use unscheudleUpdateForTarget.如果你想取消 "update" ,可以使用 unscheudleUpdateForTarget
*/
void unscheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget);
void unscheduleUpdateForTarget(const CCObject *pTarget);
void unscheduleAllForTarget(CCObject *pTarget);
/** Unschedules all selectors from all targets.
*/
void unscheduleAll(void);
/** Unschedules all selectors from all targets with a minimum priority.//取消优先级为mininum的target的所有selector
You should only call this with kCCPriorityNonSystemMin or higher.你应该只在使用 kPriorityNonSystemMin or higher 时调用这个方法
*/
void unscheduleAllWithMinPriority(int nMinPriority);
/** The scheduled script callback will be called every 'interval' seconds.scheduled 脚本回调每一个 'interval'(间隔、以秒为单位)都会被调用
If paused is YES, then it won't be called until it is resumed.如果 paused 的值是 true, 那么他不会被调用除非他被 resumed
If 'interval' is 0, it will be called every frame.如果 'interval'(间隔,以秒为单位)是 0, 他每一帧都会被调用
return schedule script entry ID, used for unscheduleScriptFunc().返回 schedule script id,用于 unscheduleScriptFunc().
*/
unsigned int scheduleScriptFunc(unsigned int nHandler, float fInterval, bool bPaused);
/** Unschedule a script entry. */取消一个脚本项
void unscheduleScriptEntry(unsigned int uScheduleScriptEntryID);
//暂停target的所有计时器调度
void pauseTarget(CCObject *pTarget);
void resumeTarget(CCObject *pTarget);
bool isTargetPaused(CCObject *pTarget);
/** Pause all selectors from all targets.
*/
CCSet* pauseAllTargets();
/** Pause all selectors from all targets with a minimum priority. 取消优先级为minimum 的所有target的所有selector
You should only call this with kCCPriorityNonSystemMin or higher.你应该只在使用 kPriorityNonSystemMin or higher 时调用这个方法
*/
CCSet* pauseAllTargetsWithMinPriority(int nMinPriority);
/** Resume selectors on a set of targets. //恢复set中的target
This can be useful for undoing a call to pauseAllSelectors. //在pauseAllSelectors时可以使用
@since v2.0.0
*/
void resumeTargets(CCSet* targetsToResume);
private:
void removeHashElement(struct _hashSelectorEntry *pElement);
void removeUpdateFromHash(struct _listEntry *entry);
// update specific
voidpriorityIn(struct _listEntry **ppList, CCObject *pTarget, int nPriority, bool bPaused);
//参数用于create一个tHashUpdateEntry 然后加入(根据nPriority找位置)m_pHashForUpdates
//参数1、事件节点 2、target 3、优先级 在scheduleUpdateForTarget中调用
void CCScheduler::priorityIn(tListEntry **ppList, CCObject *pTarget, int nPriority, bool bPaused)
{
tListEntry *pListElement = (tListEntry *)malloc(sizeof(*pListElement)); //事件节点(update selector实现的)
pListElement->target = pTarget;
pListElement->priority = nPriority;
pListElement->paused = bPaused;
pListElement->next = pListElement->prev = NULL;
pListElement->markedForDeletion = false;
// empty list ?
if (! *ppList)
{
DL_APPEND(*ppList, pListElement);
}
else //把ppList加入到优先级大于给出的优先级的地方
{
bool bAdded = false;
for (tListEntry *pElement = *ppList; pElement; pElement = pElement->next) //越往后(->next)优先级越高
{
if (nPriority < pElement->priority)
{
if (pElement == *ppList)
{
DL_PREPEND(*ppList, pListElement);
}
else
{
pListElement->next = pElement;
pListElement->prev = pElement->prev;
pElement->prev->next = pListElement;
pElement->prev = pListElement;
}
bAdded = true;
break;
}
}
// Not added? priority has the higher value. Append it.
if (! bAdded)
{
DL_APPEND(*ppList, pListElement);
}
}
// update hash entry for quick access
tHashUpdateEntry *pHashElement = (tHashUpdateEntry *)calloc(sizeof(*pHashElement), 1);
pHashElement->target = pTarget;
pTarget->retain();
pHashElement->list = ppList;
pHashElement->entry = pListElement;
HASH_ADD_INT(m_pHashForUpdates, target, pHashElement);
}
voidappendIn(struct _listEntry **ppList, CCObject *pTarget, bool bPaused);
//参数用于create(直接附加)一个tHashUpdateEntry 然后加入m_pHashForUpdates
void CCScheduler::appendIn(_listEntry **ppList, CCObject *pTarget, bool bPaused)
{
tListEntry *pListElement = (tListEntry *)malloc(sizeof(*pListElement));
pListElement->target = pTarget;
pListElement->paused = bPaused;
pListElement->markedForDeletion = false;
DL_APPEND(*ppList, pListElement);
// update hash entry for quicker access
tHashUpdateEntry *pHashElement = (tHashUpdateEntry *)calloc(sizeof(*pHashElement), 1);
pHashElement->target = pTarget;
pTarget->retain();
pHashElement->list = ppList;
pHashElement->entry = pListElement;
HASH_ADD_INT(m_pHashForUpdates, target, pHashElement);
}
protected:
float m_fTimeScale;
//
// "updates with priority" stuff
//
struct _listEntry *m_pUpdatesNegList; // list of priority < 0
struct _listEntry *m_pUpdates0List; // list priority == 0
struct _listEntry *m_pUpdatesPosList; // list priority > 0
struct _hashUpdateEntry *m_pHashForUpdates; //用于快速找到链表入口来暂停和删除“事件”
// Used for "selectors with interval"
struct _hashSelectorEntry *m_pHashForTimers;
struct _hashSelectorEntry *m_pCurrentTarget;
bool m_bCurrentTargetSalvaged;
// If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
bool m_bUpdateHashLocked;
CCArray* m_pScriptHandlerEntries;
};
// end of global group
/// @}
NS_CC_END
#endif // __CCSCHEDULER_H__