Laya1.x Timer小记

Timer是时钟管理类,在Laya初始化的时候会创建一个实例,通过Laya.timer访问。

TimerHandler
  • TimerHandler是对每一个定时任务的封装,每次调用frameOnce、frameLoop、once、loop或者callLayer都会产生一个TimerHandler实例。
  • TimerHandler会缓存传入的参数(args),当定时器触发时,会将对应的args传递给对应回调。
public var key:int;             //唯一key,用于快速找到对应handler
public var repeat:Boolean;      //是否是重复调用   分别对应 once/loop
public var delay:int;           //延时
public var userFrame:Boolean;   // true表示使用帧计时  false表示使用时间计时
public var exeTime:int;         //下次执行的时间
public var caller:*             //调用者
public var method:Function;     //调用方法
public var args:Array;          //触发时的参数
public var jumpFrame:Boolean;   //时钟是否跳帧。基于时间的循环回调,单位时间间隔内,如能执行多次回调,出于性能考虑,引擎默认只执行一次,设置jumpFrame=true后,则回调会连续执行多次

public function clear():void {
    caller = null;
    method = null;
    args = null;
}

public function run(withClear:Boolean):void {
    var caller:* = this.caller;
    /*[IF-FLASH]*/
    if ((caller is Node) && caller.destroyed)
        /*[IF-FLASH]*/
        return clear();
    //[IF-SCRIPT] if (caller && caller.destroyed) return clear();
    var method:Function = this.method;
    var args:Array = this.args;
    withClear && clear();
    if (method == null) return;
    args ? method.apply(caller, args) : method.call(caller);
}
Timer数据类型定义
/**@private */
private static var _pool:Array = [];   //TimerHandler池

/*[DISABLE-ADD-VARIABLE-DEFAULT-VALUE]*/
/** 两帧之间的时间间隔,单位毫秒。*/
private var _delta:int = 0;     
/** 时针缩放。*/
public var scale:Number = 1;
/** 当前帧开始的时间。*/
public var currTimer:Number = _now();
/** 当前的帧数。*/
public var currFrame:int = 0;
/**@private */
private var _lastTimer:Number = _now(); //上一帧的时间
/**@private */
private var _mid:int = 1;               //用于生成唯一key
/**@private */
/*[IF-FLASH]*/                          //TimerHandler的map  用于查找Handler(包括Later的handler)
private var _map:flash.utils.Dictionary = new flash.utils.Dictionary(true);
//[IF-JS] private var _map:Array = [];
/**@private */
private var _laters:Array = [];         //存放callLater创建的handler
/**@private */
private var _handlers:Array = [];       //存放非callLater创建的handler,包括frameOnce、frameLoop、once、loop
/**@private */
private var _temp:Array = [];           //临时数组,用于清理
/**@private */
private var _count:int = 0;             //记录handler.method为空的数量,检测是否清理
初始化
/**@private */
protected function _init():void {
    Laya.timer && Laya.timer.frameLoop(1, this, _update);
}

除了Laya.timer之外,其他的timer的实例都是注册到Laya.timer的frameLoop中。

_create方法
  • 创建对应的TimerHandler。
  • 如果coverBefore并且已经注册过相同Handler,则覆盖之前的handler
  • 设置对应参数,并计算下一次执行的时间。
  • 为Handler创建唯一key,添加到_map中,用于快速查找。
  • 将handler放到_handler数组中,用于_update时遍历。

frameOnce、frameLoop、once、loop实现上都是调用_create方法,传入对应的参数,将handler注册到timer中,等待_update执行相关计算。

/** @private */
public function _create(useFrame:Boolean, repeat:Boolean, delay:int, caller:*, method:Function, args:Array, coverBefore:Boolean):TimerHandler {
    //如果延迟为0,则立即执行
    if (!delay) {
        method.apply(caller, args);
        return null;
    }
    
    //先覆盖相同函数的计时
    if (coverBefore) {
        var handler:TimerHandler = _getHandler(caller, method);
        if (handler) {
            handler.repeat = repeat;
            handler.userFrame = useFrame;
            handler.delay = delay;
            handler.caller = caller;
            handler.method = method;
            handler.args = args;
            handler.exeTime = delay + (useFrame ? this.currFrame : this.currTimer + _now() - _lastTimer);
            return handler;
        }
    }
    
    //找到一个空闲的timerHandler
    handler = _pool.length > 0 ? _pool.pop() : new TimerHandler();
    handler.repeat = repeat;
    handler.userFrame = useFrame;
    handler.delay = delay;
    handler.caller = caller;
    handler.method = method;
    handler.args = args;
    handler.exeTime = delay + (useFrame ? this.currFrame : this.currTimer + _now() - _lastTimer) + 1;
    
    //索引handler
    _indexHandler(handler);
    
    //插入数组
    _handlers.push(handler);
    
    return handler;
}
callLater
  • callLater使用延时执行,再Timer.update执行末尾调用。
  • 如果对应的caller和method已经注册过,则不会重复注册。
  • 创建的TimerHandler会放到_laters数组中。
_update
  • 计算当前帧和当前时间。
  • 计算delta。
  • 遍历handler数组,检查时间/帧是否超过了handler的exeTime。
  • 超过时间handler执行回调,如果是once则将handler的caller和method设置为空;如果是loop则执行回调,并计算下次执行的时间。如果下次调用的时间间隔内,可以触发多次回调,默认情况下执行执行一次回调。如果设置为jumpFrame则会调用多次回调(如delay为1毫秒,delta为30毫秒,则下个update时,会调用30次回调)。
  • 遍历数组时,会记录method为空的handler的数量,当数量为30或者200帧时,会清理一次没用的handler,将没用的handler回收到池中。
  • 执行完所有handler之后,遍历所有laters数组,执行callLater所注册的回调。执行完成后,清理所有laters数组。
/**
 * @private
 * 帧循环处理函数。
 */
public function _update():void {
    if (scale <= 0) {
        _lastTimer =_now();
        return;
    }
    var frame:int = this.currFrame = this.currFrame + scale;
    var now:Number = _now();
    _delta = (now - _lastTimer) * scale;
    var timer:Number = this.currTimer = this.currTimer + _delta;
    _lastTimer = now;
    
    //处理handler
    var handlers:Array = this._handlers;
    _count = 0;
    for (i = 0, n = handlers.length; i < n; i++) {
        handler = handlers[i];
        if (handler.method !== null) {
            var t:int = handler.userFrame ? frame : timer;
            if (t >= handler.exeTime) {
                if (handler.repeat) {
                    if (!handler.jumpFrame) {
                        handler.exeTime += handler.delay;
                        handler.run(false);
                        if (t > handler.exeTime) {
                            //如果执行一次后还能再执行,做跳出处理,如果想用多次执行,需要设置jumpFrame=true
                            handler.exeTime += Math.ceil((t - handler.exeTime) / handler.delay) * handler.delay;
                        }
                    } else {
                        while (t >= handler.exeTime) {
                            handler.exeTime += handler.delay;
                            handler.run(false);
                        }
                    }
                } else {
                    handler.run(true);
                }
            }
        } else {
            _count++;
        }
    }
    
    if (_count > 30 || frame % 200 === 0) _clearHandlers();
    
    //处理callLater
    var laters:Array = this._laters;
    for (var i:int = 0, n:int = laters.length - 1; i <= n; i++) {
        var handler:TimerHandler = laters[i];
        if (handler.method !== null) {
            /*[IF-FLASH]*/
            _map[handler.method] = null;
            //[IF-SCRIPT]_map[handler.key] = null;
            handler.run(false);
        }
        _recoverHandler(handler);
        i === n && (n = laters.length - 1);
    }
    laters.length = 0;
}
其他
  • Laya.timer._update是在Laya.stage.loop中调用,Laya.stage.loop是在Render中调用。

  • 在Frash中,监听enterFrame事件。

  • 在js中则是注册requestAnimationFrame,来进入渲染帧。

  • 当stage不可见时(如切到后台),则timer._update每一秒触发一次。一秒钟一帧,当切回前台后,帧率恢复正常。

  • update是在渲染之前执行。
  • Laya.stage控制实际帧率,根据Laya.stage.frameRate。

转载于:https://www.cnblogs.com/chiguozi/p/9755808.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值