cocos2d-x 源码剖析(11)

好久没用动笔写博客了,今天是1024节,还是要表示下。而且今天检查邮箱发现了5个垃圾评论,觉得很高兴,也要来篇文章庆祝下。哈哈。
时间隔得太久,我都不记得我讲到那里来了。原来是打算将几个特殊点的Action为大家结尾,最后一看源码,发现有点杂乱,待我整理好之后再写。今天来讲一讲CCScheduler。之前讲过,在ActionManager创建出来之后立马就加入到CCScheduler中去了,然后用ActionManager来控制不同Action的Update。也就是说CCScheduler是Action能工作的保障。我再贴这段代码回顾下:

// scheduler
m_pScheduler = new CCScheduler();
// action manager
m_pActionManager = new CCActionManager();
m_pScheduler->scheduleUpdateForTarget(m_pActionManager, kCCPrioritySystem, false);


而在mainLoop中的drawScene中也只有一个除绘制以外的逻辑,那就是update。

// Draw the Scene
void CCDirector::drawScene(void)
{
    // calculate "global" dt
    calculateDeltaTime();
 
    //tick before glClear: issue #533
    if(!m_bPaused)
    {
        m_pScheduler->update(m_fDeltaTime);
    }
 
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  ......
}


所有的根源都是那个m_pScheduler的update。可见CCScheduler的重要性。CCScheduler的构造函数只是简单的初始化了几个指针变量,没做任何的init逻辑处理。而且它不是单间,虽说cocos2d-x只支持一个scheduler update。需要了解CCScheduler还有一个伴生的概念叫做CCTimer,我们可以叫做定时器。CCScheduler内建了对update函数的支持,如果你要Scheduler自定义的函数就要借助CCTimer了,它就相当于一个适配器。

以上面那个scheduleUpdateForTarget为例,我们看起代码:

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);
    }
    else if (nPriority < 0)
    {
        priorityIn(&m_pUpdatesNegList, pTarget, nPriority, bPaused);
    }
    else
    {
        // priority > 0
        priorityIn(&m_pUpdatesPosList, pTarget, nPriority, bPaused);
    }
}


前面的检测保障其不能重复添加,但是允许在一帧之间先删除再添加。我们可以发现这部分代码和ActionManager是很像的, 这种标记删除的手法在游戏开发中很常见,如果你要统一管理自己的对象,记得也要采用这种方法,可以避免掉很多问题。与ActionManager不同的是,他内部采用了三个update容器来管理。我们看到

#define kCCPrioritySystem INT_MIN

可见,Action的update的优先级是最高的。从注释上我们可以看出,默认的update的优先级是0,而且没有特殊情况下优先级大于0的容器中是没有元素的。这种设计是必要的,因为有些逻辑比较分散,最后又要统一处理。添加到大于0的优先级中就可以了。

上面可以看到真正添加到update容器中的是priorityIn这个函数,添加到容器的步骤要注意几点,新建一个容器元素,排好优先级,而且有个特殊的地方是它用了一个Hash表来快速的update这个列表中的函数。所以还要添加到Hash表中去。上面就是CCScheduler update的大致流程。我们知道CCScheduler除了update之外,还可以指定自定义的函数,也就是下面这个函数做的:

scheduleSelector(SEL_SCHEDULE pfnSelector,
 CCObject *pTarget, float fInterval, 
 unsigned int repeat, float delay, bool bPaused)

这个函数的参数值简直是丧心病狂,好在CCNode再次封装了一次。这种手法与Action类似,我就不多做介绍了。观其代码:

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);
 
    if(!pElement)
    {
        pElement=(tHashTimerEntry*)calloc(sizeof(*pElement),1);
        pElement->target=pTarget;
        if(pTarget)
        {
            pTarget->retain();
        }
        HASH_ADD_INT(m_pHashForTimers,target,pElement);
 
        // Is this the 1st element ? Then set the pause level to all the selectors of this target
        pElement->paused=bPaused;
    }
    else
    {
        CCAssert(pElement->paused==bPaused,"");
    }
 
    if(pElement->timers==NULL)
    {
        pElement->timers=ccArrayNew(10);
    }
    else
    {
        for(unsignedinti=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=newCCTimer();
    pTimer->initWithTarget(pTarget,pfnSelector,fInterval,repeat,delay);
    ccArrayAppendObject(pElement->timers,pTimer);
    pTimer->release();    
}


这些操作简直与Action如出一辙,他为每个新加的Target分配了10个定时器的空间,而且允许重复进入(其作用是更新参数)。再看其update函数,可以说这个函数是cocos2d-x的逻辑主体,他首先处理3个update容器中的元素,再处理自定义的timer,最后删除标记为删除的管理对象。代码我就不贴了。其他一些管理逻辑和要注意的问题与ActionManager是类似的,就不再多啰嗦了。大家可以对比来加深印象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值