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. LR-事务

    一.对事务的理解 在LR中什么是事务,事务是记录从客户端到服务器端,服务器端返回到客户端应答的时间,可以反映出一个操作所用的时间.那么事务的时间主要是由响应时间.事务自身时间.浪费时间(wasted ...

  2. 转: kali msfvenom生成木马

    kali msfvenom生成木马 转:https://blog.csdn.net/qq_33391644/article/details/79266724 msfvenom是msfpayload,m ...

  3. hihocoder 1500 EL SUENO

    树上背包. 简单的树形$dp$,计算出摧毁每一个节点所需的最小费用,背包即可. #include<bits/stdc++.h> using namespace std; struct X ...

  4. Sharepoint 2010 TimerJob重复

    昨天被TimerJob困扰了一天.原因就是TimerJob当中会有一个Httpwebrequest GET请求一个Application Page进行一些操作(其中有一个操作是发送邮件).但是发现随机 ...

  5. JavaScript三种数据类型之间的互转

    一:number<===>string  数字类型和字符串类型之间的互相转换 number===>string 数字转字符串有三种方式: 1.在数字后面 +“ ”; 2.利用字符串的 ...

  6. scrapy实现多级页面的抓取时使用meta传递item数据的问题(转)

    name = 'doubanzufang'start_urls = ['https://www.douban.com/group/tianhezufang/discussion?start=50'] ...

  7. 洛谷——P2071 座位安排 seat.cpp/c/pas

    P2071 座位安排 seat.cpp/c/pas 题目背景 公元二零一四年四月十七日,小明参加了省赛,在一路上,他遇到了许多问题,请你帮他解决. 题目描述 已知车上有N排座位,有N*2个人参加省赛, ...

  8. Xamarin.Forms XAML的辅助功能Code Snippet

    Xamarin.Forms XAML的辅助功能Code Snippet   在Visual Studio中,使用Code Snippet(代码片段)功能可以减少基础代码的编写量,如常见的标签.循环语句 ...

  9. 初探 Spring Boot

    近些年Spring Boot都特别火,一直都想来学习学习,奈何近期公司项目繁忙,一直都没有时间来学习,今天终于是休息一天,于是来一睹 SpringBoot 的风采. 一.什么是Spring Boot ...

  10. 按考分对学生排序 Exercise08_03

    /** * @author 冰樱梦 * 时间:2018年12月 * 题目:按考分对学生排序 * */ public class Exercise08_03 { public static void m ...