scheduler 这个类, 负责了引擎的自定义更新, 及定时更新相关的操作, 看看下面的代码,很熟悉吧。
 
schedule(schedule_selector(HelloWorld::update), );
 
它是如何工作的呢, 咱还记得前面mainLoop->drawScene() 的调用 吗?里面就有调用Scheduler::update(float dt)
 
我们用一个例子代入一下, 就拿上面的代码来说, 分2个步:
1 注册更新调用 
2 引擎调用用户的更新调用函数。 
 
1 注册更新
 
schedule(schedule_selector(HelloWorld::update), 10);
 
流程: 
 
1 申明一个tHashTimerEntry *element
2 查询当前是否有注册过这个target的更新
3 没有则添加一个element更新元素, 有则不添加了,直接使用这个为当前的更新元素。 
4 判断当前的更新元素中是否有指定的Timer, 没有则直接添加, 有则不加了, 直接返回。 
5 把selector, target 封装为timer
6 把timer 加入到当前element的timers中. 
7 完成整个的注册流程。 
 
代码:
void Scheduler::schedule(SEL_SCHEDULE selector, Ref *target, float interval, unsigned int repeat, float delay, bool paused)
{
CCASSERT(target, "Argument target must be non-nullptr"); tHashTimerEntry *element = nullptr;
HASH_FIND_PTR(_hashForTimers, &target, element); if (! element)
{
element = (tHashTimerEntry *)calloc(sizeof(*element), );
element->target = target; HASH_ADD_PTR(_hashForTimers, target, element); // Is this the 1st element ? Then set the pause level to all the selectors of this target
element->paused = paused;
}
else
{
CCASSERT(element->paused == paused, "");
} if (element->timers == nullptr)
{
element->timers = ccArrayNew();
}
else
{
for (int i = ; i < element->timers->num; ++i)
{
TimerTargetSelector *timer = static_cast<TimerTargetSelector*>(element->timers->arr[i]); if (selector == timer->getSelector())
{
CCLOG("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer->getInterval(), interval);
timer->setInterval(interval);
return;
}
}
ccArrayEnsureExtraCapacity(element->timers, );
} TimerTargetSelector *timer = new (std::nothrow) TimerTargetSelector();
timer->initWithSelector(this, selector, target, interval, repeat, delay);
ccArrayAppendObject(element->timers, timer);
timer->release();
}
总结一下:
 
1》Scheudler 内部有一个hashTable, _hashForTimers( UT_hash是一个开源的hashTable数据结构,具体的使用网上可以查到。 ), 存放在着所有的注册。 
2》这个hashTable的Key = target, Value = 是一个tHashTimerEntry类型的数据结构,tHashTimerEntry这个结构存储着一个timers 数组,
3》这个timers数组封装并保存了用户传入的target, 及select方法。 
 
见如下两个关键的数据结构, 还有一个UT_hash_handle 这里不展开了,这是个开源的hashtable 详细看一下下面的参考:  
 
typedef struct _hashSelectorEntry
{
ccArray *timers;
void *target;
int timerIndex;
Timer *currentTimer;
bool currentTimerSalvaged;
bool paused;
UT_hash_handle hh;
} tHashTimerEntry; timers 存放的是Timer 类型的对象,TimerTargetSelector 是Timer的子类,主要存放了selector, 及target class CC_DLL Timer : public Ref
{
protected:
Timer();
public:
/** get interval in seconds */
inline float getInterval() const { return _interval; };
/** set interval in seconds */
inline void setInterval(float interval) { _interval = interval; }; void setupTimerWithInterval(float seconds, unsigned int repeat, float delay); virtual void trigger() = ;
virtual void cancel() = ; /** triggers the timer */
void update(float dt); protected: Scheduler* _scheduler; // weak ref
float _elapsed;
bool _runForever;
bool _useDelay;
unsigned int _timesExecuted;
unsigned int _repeat; //0 = once, 1 is 2 x executed
float _delay;
float _interval;
}; class CC_DLL TimerTargetSelector : public Timer
{
public:
TimerTargetSelector(); bool initWithSelector(Scheduler* scheduler, SEL_SCHEDULE selector, Ref* target, float seconds, unsigned int repeat, float delay); inline SEL_SCHEDULE getSelector() const { return _selector; }; virtual void trigger() override;
virtual void cancel() override; protected:
Ref* _target;
SEL_SCHEDULE _selector;
};
 
2 引擎调用用户的更新调用函数。 
 
其实调用还是在mainLoop里调用的, 具体位置在Director::drawScene() 里,之前的章节也介绍过这个位置 。 
主要是调用了。 

Scheduler::update(dt)

// main loop
void Scheduler::update(float dt)
{
_updateHashLocked = true; if (_timeScale != 1.0f)
{
dt *= _timeScale;
}
..
// Iterate over all the custom selectors
for (tHashTimerEntry *elt = _hashForTimers; elt != nullptr; )
{
_currentTarget = elt;
_currentTargetSalvaged = false; if (! _currentTarget->paused)
{
// The 'timers' array may change while inside this loop
for (elt->timerIndex = ; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
{
elt->currentTimer = (Timer*)(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 = nullptr;
}
} // 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 (_currentTargetSalvaged && _currentTarget->timers->num == )
{
removeHashElement(_currentTarget);
}
}
具体操作: 
 
1>  遍历当前自身内部hashTable, _hashForTimers. 
2>  得到内部存储的每个tHashTimerEntity, 这个类型内部存储着array 类型的timers, 就是这个timers,存储着我们注册更新的调用。 
3> 遍历这个每个timer的update(),
Timer这个类封装了我们在做自定义调用时传来的参数.
Timer的update() 会判断当前时间差, 是否应该进行调用我们注册的函数。 如果需要则触发调用
 

void TimerTargetSelector::trigger()
{
if (_target && _selector)
{
(_target->*_selector)(_elapsed);
}
} void Timer::update(float dt)
{
..
..
if (_runForever && !_useDelay)
{//standard timer usage
_elapsed += dt;
if (_elapsed >= _interval)
{
trigger(); _elapsed = ;
}
}
}
参考:
       uthash 哈希Table . 
 
 
  另外,uthash的英文使用文档介绍可从下面网址获得:
 

4 cocos2dx 3.0 源码分析- scheduler的更多相关文章

  1. 3 cocos2dx 3.0 源码分析-mainLoop详细

    简述:   我靠上面图是不是太大了, 有点看不清了.  总结一下过程: 之前说过的appController 之后经过了若干初始化, 最后调用了displayLinker 的定时调用, 这里调用了函数 ...

  2. 5 cocos2dx 3.0源码分析 渲染 render

    渲染,感觉这个挺重要了,这里代入一个简单的例子 Sprite 建立及到最后的画在屏幕上, 我们描述一下这个渲染的流程:   1 sprite 初始化(纹理, 坐标,及当前元素的坐标大小信息) 2 主循 ...

  3. 2 cocos2dx 3.0 源码分析-Director

    Director 导演类, 这个类在整个引擎中担当着最重要的角色, 先看看它是如何初始化的,它共管理了哪些内容呢?    1初始化- 更新处理Scheduler   Scheduler 这个类负责用户 ...

  4. AFNetWorking3.0源码分析

    分析: AFNetWorking(3.0)源码分析(一)——基本框架 AFNetworking源码解析 AFNetworking2.0源码解析<一> end

  5. Solr5.0源码分析-SolrDispatchFilter

    年初,公司开发法律行业的搜索引擎.当时,我作为整个系统的核心成员,选择solr,并在solr根据我们的要求做了相应的二次开发.但是,对solr的还没有进行认真仔细的研究.最近,事情比较清闲,翻翻sol ...

  6. Solr4.8.0源码分析(25)之SolrCloud的Split流程

    Solr4.8.0源码分析(25)之SolrCloud的Split流程(一) 题记:昨天有位网友问我SolrCloud的split的机制是如何的,这个还真不知道,所以今天抽空去看了Split的原理,大 ...

  7. Solr4.8.0源码分析(24)之SolrCloud的Recovery策略(五)

    Solr4.8.0源码分析(24)之SolrCloud的Recovery策略(五) 题记:关于SolrCloud的Recovery策略已经写了四篇了,这篇应该是系统介绍Recovery策略的最后一篇了 ...

  8. Solr4.8.0源码分析(23)之SolrCloud的Recovery策略(四)

    Solr4.8.0源码分析(23)之SolrCloud的Recovery策略(四) 题记:本来计划的SolrCloud的Recovery策略的文章是3篇的,但是没想到Recovery的内容蛮多的,前面 ...

  9. Solr4.8.0源码分析(22)之SolrCloud的Recovery策略(三)

    Solr4.8.0源码分析(22)之SolrCloud的Recovery策略(三) 本文是SolrCloud的Recovery策略系列的第三篇文章,前面两篇主要介绍了Recovery的总体流程,以及P ...

随机推荐

  1. 关于<c:if>没有<c:else>解决方案-转载

    <c:if>没有<c:else>可以用<c:choose>来取代结构: <c:choose> <c:when test=""& ...

  2. java -jar demo.jar

    部署springboot项目 生成jar包其实还是依赖springboot的jar才能跑起来,为什么呢? 1.在C盘手工创建了一个文件夹,是拷贝了demo.jar这个jar包运行是报错的. 2.在D: ...

  3. Scrapy爬取女神照片

    使用Scrapy趴一趴美女图 Scrapy,Python开发的一个快速,高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据.Scrapy用途广泛,可以用于数据挖掘.监测和自 ...

  4. Redis学习篇(十一)之发布订阅

    PUBLISH/SUBSCRIBE 发布订阅的原理 包含两个角色,一个是发布者, 一个是订阅者 订阅者可以订阅一个或者多个频道(channel) 发布者可以向指定的频道发布信息 通过SUBSCRIBE ...

  5. [HNOI2006]最短母串问题 --- AC自动机 + 隐式图搜索

    [HNOI2006]最短母串问题 题目描述: 给定n个字符串(S1,S2.....,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,......,Sn)都是T的子串. 输入格式: 第 ...

  6. bzoj 1098

    对于关系,看其是否是“等价关系”,即满足:自反,传递,对称. 如果是可以用并查集来连接等价类. 这道题是求原图补集的联通快个数,考虑原图度最少的点(由鸽巢原理,最多为2*e/n个). 先将未与其连边的 ...

  7. Android Studio 2.3更换默认的ConstraintLayout布局

    首先打开你的Android Sudio安装目录,我的为D:\Program Files\Android\Android Studio,进入到以下文件夹\plugins\android\lib\temp ...

  8. ACM -- 算法小结(二)错排公式的应用

    pala提出的问题: 十本不同的书放在书架上.现重新摆放,使每本书都不在原来放的位置.有几种摆法?  这个问题推广一下,就是错排问题: n个有序的元素应有n!种不同的排列.如若一个排列式的所有的元素都 ...

  9. VK Cup 2016 - Qualification Round 2 B. Making Genome in Berland 水题

    B. Making Genome in Berland 题目连接: http://www.codeforces.com/contest/638/problem/B Description Berlan ...

  10. mysqldump之字符集问题解决

    最近导数据的需求真多,年底了大家都要做分析吗?近期使用mysqldump导出的中文出现乱码问题. mysqldump -uroot -ppassword -S /tmp/mysql9991.sock ...