源码版本 3.1r,转载请注明
我也终于不out了,开始看3.x的源码了,此时此刻的心情只能是wtf!!!!!!!!!!不过也终于告别CC时代了。
cocos2d-x 源码分析目录
http://blog.csdn.net/u011225840/article/details/31743129
1.继承结构
没错,是两张图。(你没有老眼昏花。。我脑子也没有秀逗。。)Ref就是原来的CCObject,而Timer类是与Scheduler类密切相关的类,所以需要把他们放在一起说。Timer和Scheduler的关系就像Data和DataManager的关系。
2.源码分析
2.1 Timer
2.1.1 Timer中的数据
Timer类定义了一个行为执行的间隔,执行的次数等,可以理解为定时器的数据类,而具体的定时器的行为,定义在子类中。Timer中的数据如下:
//_elapsed 上一次执行后到现在的时间
//timesExecuted 执行的次数
//interval 执行间隔
//useDelay 是否使用延迟执行
float _elapsed;
bool _runForever;
bool _useDelay;
unsigned int _timesExecuted;
unsigned int _repeat; //0 = once, 1 is 2 x executed
float _delay;
float _interval;
2.1.2 Update函数
void Timer::update(float dt)
{
//update方法使用的是模板设计模式,将trigger与cancel的实现交给子类。
if (_elapsed == -1)
{
_elapsed = 0;
_timesExecuted = 0;
}
//四种情况
/*
1.永久执行并且不使用延迟:基本用法,计算elapsed大于interval后执行一次,永不cancel。
2.永久执行并且使用延迟:当elapsed大于延迟时间后,执行一次后,进入情况1.
3.不永久执行并且不使用延迟:情况1结束后,会判断执行次数是否大于重复次数,大于后则cancel。
4.不永久执行并且使用延迟:情况2结束后,进入情况3.
*/
else
{
if (_runForever && !_useDelay)
{//standard timer usage
_elapsed += dt;
if (_elapsed >= _interval)
{
trigger();
_elapsed = 0;
}
}
else
{//advanced usage
_elapsed += dt;
if (_useDelay)
{
if( _elapsed >= _delay )
{
trigger();
_elapsed = _elapsed - _delay;
_timesExecuted += 1;
_useDelay = false;
}
}
else
{
if (_elapsed >= _interval)
{
trigger();
_elapsed = 0;
_timesExecuted += 1;
}
}
if (!_runForever && _timesExecuted > _repeat)
{ //unschedule timer
cancel();
}
}
}
}
正如我注释中所说,update使用了模板方法的设计模式思想,将trigger与cancel调用的过程写死,但是不同的子类实现trigger和cancel的方式不同。
另外需要注意的是,Schedule使用时delay的需求,当有delay与没有delay我在源码中已经分析的很清楚了。
2.2 TimerTargetSelector && TimerTargetCallback
前者是针对类(继承自Ref)中的method进行定时,而后者是针对function(普通函数)。
前者绑定的类型是SEL_SCHEDULE(你问我这是什么?)typedef void (Ref::*SEL_SCHEDULE)(float);一个指向Ref类型的method指针,并且该method必须满足参数是float,返回值是void。后者绑定的类型是ccSchedulerFunc---------typedef std::function<void(float)> ccSchedulerFunc;这是虾米?这是c++11的新特性,其实就是一个函数指针。
从他们实现的trigger方法中可以更好的看清这一切。
void TimerTargetSelector::trigger()
{
if (_target && _selector)
{
(_target->*_selector)(_elapsed);
}
}
void TimerTargetCallback::trigger()
{
if (_callback)
{
_callback(_elapsed);
}
}
最后说一下,TargetCallback中含有一个key,而前者没有。这在下面的源码分析中会看到。(其实原理很简单,SEL_SCHEDULE可以当成key,ccSchedulerFunc不能,因为前者有唯一的标识,如果你不懂这点,欢迎去复习下c++的指向类中方法的函数指针)
Ref* _target;
SEL_SCHEDULE _selector;
------ ------------------------
void* _target;
ccSchedulerFunc _callback;
std::string _key;
2.3 Scheduler
2.3.1 Schedule && UnSchedule
Schedule有四种重载方法。其中各有两种针对不同的Timer子类,但是都大同小异,在此之前