CCScheduler(调度器 两种回调1、update回调(通过object的update函数实现所以每次调用) 2、一般回调(通过timer timer是可以设置fSeconds的可变调用间隔))

#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);

void CCTimer::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);
// 这里要求 初始化时传入的  Selector 是m_pTarget的成员函数。 那为什么多此一举不直接传入一个target???
                }
                if (m_nScriptHandler)
                {
                    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);
                    }
                    if (m_nScriptHandler)
                    {
                        CCScriptEngineManager::sharedManager()->getScriptEngine()->executeSchedule(m_nScriptHandler, m_fElapsed);
                    }
                    m_fElapsed = m_fElapsed - m_fDelay;
                    m_uTimesExecuted += 1;
                    m_bUseDelay = false;
                }
            }
            else
            {
                if (m_fElapsed >= m_fInterval)
                {
                    if (m_pTarget && m_pfnSelector)
                    {
                        (m_pTarget->*m_pfnSelector)(m_fElapsed);
                    }
                    if (m_nScriptHandler)
                    {
                        CCScriptEngineManager::sharedManager()->getScriptEngine()->executeSchedule(m_nScriptHandler, m_fElapsed);
                    }
                    m_fElapsed = 0;
                    m_uTimesExecuted += 1;
                }
            }
            if (!m_bRunForever && m_uTimesExecuted > m_uRepeat)
            {    //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++的结构体更方便

typedef struct _listEntry   //调度器中 调度的“事件(这个事件由target的成员函数来具体实现 )”节点  用于update回调
{
    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;

typedef struct _hashUpdateEntry //“事件”链表的哈希表   
{
    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;

// Hash Element used for "selectors with interval"
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);

void CCScheduler::update(float dt)
{
    m_bUpdateHashLocked = true;
    if (m_fTimeScale != 1.0f)
    {
        dt *= m_fTimeScale;
    }
   

 // Iterate over all the Updates' selectors    这种类型的回调(selectors更快 效率更高
    tListEntry *pEntry, *pTmp;
    // updates with priority < 0
    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      这种类型的回调(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;
}


//  前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);

void CCScheduler::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");
    tHashTimerEntry *pElement = NULL;
    HASH_FIND_INT(m_pHashForTimers, &pTarget, pElement);
//哈希表m_pHashForTimers中根据键pTarget查找 tHashTimerEntry 找到后赋给pElement
    if (! pElement)
    {
        pElement = (tHashTimerEntry *)calloc(sizeof(*pElement), 1);
        pElement->target = pTarget;
        if (pTarget)
        {
            pTarget->retain();
        }
        HASH_ADD_INT(m_pHashForTimers, target, pElement);  
//add tHashTimerEntry节点
        pElement->paused = bPaused;  //因为是第一个 所以pause掉这个target的所有selectors
    }
    else
    {
        CCAssert(pElement->paused == bPaused, "");
    }
    if (pElement->timers == NULL)
    {
        pElement->timers = ccArrayNew(10);
    }
    else 
    {
        for (unsigned int i = 0; i < pElement->timers->num; ++i)
        {
            CCTimer *timer = (CCTimer*)pElement->timers->arr[i];
            if (pfnSelector == timer->getSelector())
            {
                CCLOG("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer->getInterval(), fInterval);
                timer->setInterval(fInterval);
                return;
            }        
        }
        ccArrayEnsureExtraCapacity(pElement->timers, 1);
    }
    CCTimer *pTimer = new CCTimer(); 
    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__



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值