Egret custom timer (TimerManager Shacheng battle and Laya.timer)

 

A custom timer

Because the timer is often used in the game, such as a bullet fired ah every second, every 2 seconds Monster AI automatic steering ah

Every time I go new Timer Then addEventListener (egret.TimerEvent ... like too much trouble.

 

So a custom timer

 

Shacheng battle of two custom timer

Take a look at Shacheng battle of custom timer

Egret.Ticker principle is performed for each frame, so that the list TimerHandler plus or time frame, to check when the end time of time, on the implementation of the callback.

/**
 * Created by yangsong on 2014/11/23.
 * Timer管理器
 */
class TimerManager extends SingtonClass {
    private _handlers: Array<TimerHandler>;
    private _delHandlers: Array<TimerHandler>;
    private _currTime: number;
    private _currFrame: number;
    private _count: number;
    private _timeScale: number;
    private _isPause: boolean;
    private _pauseTime: number;

    /**
     * 构造函数
     */
    public constructor() {
        super();
        this._handlers = new Array<TimerHandler>();
        this._delHandlers = new Array<TimerHandler>();
        this._currTime = egret.getTimer();
        this._currFrame = 0;
        this._count = 0;
        this._timeScale = 1;

        egret.Ticker.getInstance().register(this.onEnterFrame, this);
    }

    /**
     * 设置时间参数
     * @param timeScale
     */
    public setTimeScale(timeScale: number): void {
        this._timeScale = timeScale;
    }

    /**
     * 每帧执行函数
     * @param frameTime
     */
    private onEnterFrame(): void {
        if (this._isPause) {
            return;
        }
        this._currFrame++;
        this._currTime = egret.getTimer();
        App.DebugUtils.start("TimerManager:");
        while (this._delHandlers.length) {
            this.removeHandle(this._delHandlers.pop());
        }
        for (var i: number = 0; i < this._count; i++) {
            var handler: TimerHandler = this._handlers[i];
            if (this._delHandlers.indexOf(handler) != -1) {
                continue;
            }
            var t: number = handler.userFrame ? this._currFrame : this._currTime;
            if (t >= handler.exeTime) {
                App.DebugUtils.start(handler.method.toString());
                handler.method.call(handler.methodObj, (this._currTime - handler.dealTime) * this._timeScale);
                App.DebugUtils.stop(handler.method.toString());
                handler.dealTime = this._currTime;
                handler.exeTime += handler.delay;
                if (!handler.repeat) {
                    if (handler.repeatCount > 1) {
                        handler.repeatCount--;
                    } else {
                        if (handler.complateMethod) {
                            handler.complateMethod.apply(handler.complateMethodObj);
                        }
                        if (this._delHandlers.indexOf(handler) == -1) {
                            this._delHandlers.push(handler);
                        }
                    }
                }
            }
        }
        App.DebugUtils.stop("TimerManager:");
    }

    private removeHandle(handler: TimerHandler): void {
        var i = this._handlers.indexOf(handler);
        if (i == -1) {
            Log.warn("what????");
            return;
        }
        this._handlers.splice(i, 1);
        ObjectPool.push(handler);
        this._count--;
    }

    private create(useFrame: boolean, delay: number, repeatCount: number, method: Function, methodObj: any, complateMethod: Function, complateMethodObj: any): void {
        //参数监测
        if (delay < 0 || repeatCount < 0 || method == null) {
            return;
        }

        //先删除相同函数的计时
        this.remove(method, methodObj);

        //创建
        Handler var: = TimerHandler ObjectPool.pop ( "TimerHandler"); 
        handler.userFrame = useFrame; 
        handler.repeat = repeatCount == 0; 
        handler.repeatCount = repeatCount; 
        handler.delay = Delay; 
        handler.method = Method; 
        handler.methodObj methodObj =; 
        handler.complateMethod = complateMethod; 
        handler.complateMethodObj = complateMethodObj; 
        handler.exeTime = Delay + (useFrame this._currFrame:? this._currTime); 
        handler.dealTime = this._currTime; 
        this._handlers.push (Handler); 
        ++ this._count; 
    } 

    / ** 
     * specified function after operation (in milliseconds) specified delay.
     * @Param delay the execution interval: ms 
     * @param method performs functions 
     * @param methodObj 执行函数所属对象
     */
    public setTimeOut (Delay: Number, Method: Function, methodObj: the any): void { 
        this.doTimer (Delay,. 1, Method, methodObj); 
    } 

    / ** 
     * run the function specified in the specified frame. 
     * @Param delay the execution interval: frame rate 
     * @param method performs functions 
     * @param methodObj perform functions relevant to the object 
     * / 
    public setFrameOut (Delay: Number, Method: Function, methodObj: the any): void { 
        this.doFrame (Delay,. 1 , Method, methodObj); 
    } 

    / ** 
     * 
     * regular implementation 
     * @param delay the execution interval: ms 
     * @param repeatCount execution times, 0 unlimited 
     * @param method functions performed
     * @Param methodObj perform functions relevant to the object 
     * / 
     * @param complateMethod complete execution of the function
     * @Param complateMethodObj completion of execution of functions relevant to the object 
     * 
     * / 
    public doTimer (Delay: Number, repeatCount: Number, Method: Function, methodObj: the any, complateMethod: Function = null, complateMethodObj: the any = null): void { 
        this.create ( to false, Delay, repeatCount, Method, methodObj, complateMethod, complateMethodObj); 
    } 

    / ** 
     * 
     * regular implementation 
     * @param delay the execution interval: frame rate 
     * @param repeatCount execution times, 0 unlimited 
     * @param method performs functions 
     * @param methodObj perform the function belongs objects 
     * @param complateMethod complete execution function 
     * @param complateMethodObj complete execution function belongs objects 
     *
    doFrame public (Delay: Number, repeatCount: Number, Method: Function, methodObj: the any, complateMethod: Function = null, complateMethodObj: the any = null): void { 
        this.create (to true, Delay, repeatCount, Method, methodObj, complateMethod, complateMethodObj); 
    } 

    / ** 
     * number execute the timer 
     * @return 
     * 
     * / 
    public GET COUNT (): number { 
        return this._count; 
    } 

    / ** 
     * clean up 
     * @param method to remove the function 
     * @param methodObj function corresponding to the object to be removed 
     * / 
    public remove (Method: function, methodObj: the any): void { 
        for (var I: Number = 0; I <this._count; I ++) { 
            var Handler: TimerHandler = this._handlers [I];
            IF (handler.method == == Method methodObj && && handler.methodObj this._delHandlers.indexOf (Handler) == -1) { 
                this._delHandlers.push (Handler); 
                BREAK; 
            } 
        } 
    } 

    / ** 
     * clean up 
     * @param methodObj function corresponding object to remove 
     * / 
    public removeAll (methodObj: the any): void { 
        for (var I: Number = 0; I <this._count; I ++) { 
            var Handler: TimerHandler = this._handlers [ I]; 
            iF (handler.methodObj == methodObj && this._delHandlers.indexOf (Handler) == -1) { 
                this._delHandlers.push(handler);
            } 
        } 
    } 

    / ** 
     * detection already exists
     * @param method
     * @param methodObj
     *
     */
    public isExists(method: Function, methodObj: any): boolean {
        for (var i: number = 0; i < this._count; i++) {
            var handler: TimerHandler = this._handlers[i];
            if (handler.method == method && handler.methodObj == methodObj && this._delHandlers.indexOf(handler) == -1) {
                return true;
            }
        }
        return false;
    }

    /**
     * 暂停
     */
    public pause(): void {
        if (this._isPause) {
            return;
        }
        this._isPause = true;
        this._pauseTime = egret.getTimer();
    }

    /**
     * 从暂停中恢复
     */
    public resume(): void {
        if (!this._isPause) {
            return;
        }
        this._isPause = false;
        this._currTime = egret.getTimer();
        var gap = this._currTime - this._pauseTime;
        for (var i: number = 0; i < this._count; i++) {
            var handler: TimerHandler = this._handlers[i];
            handler.dealTime += gap;
            if (!handler.userFrame) {
                handler.exeTime += gap;
            }
        }
    }
} 
        this.method = null;


class TimerHandler {
    / ** execution interval * / 
    public Delay: Number = 0; 
    / * if repeatedly executed * / 
    public REPEAT: Boolean; 
    / ** Repeat number * / 
    public repeatCount: Number = 0; 
    / * ** whether the frame rate used / 
    public userFrame: Boolean; 
    / ** execution time * / 
    public exeTime: Number = 0; 
    / ** handler * / 
    public Method: function; 
    / ** handler relevant to the object * / 
    public methodObj: the any; 
    / completion ** handler * / 
    public complateMethod: function; 
    / ** completion handler relevant to the object * / 
    public complateMethodObj: the any; 
    / ** last execution time * / 
    public dealTime: Number = 0; 

    / ** clean up * / 
    public Clear ( ): void { 
        this.methodObj = null;
        this.complateMethod = null;
        this.complateMethodObj = null;
    }
}

  

Laya's three timer

laya has provided a timer for developers to use, and almost Shacheng battle

 Since Date.now Laya used, then the game in the background for too long, and then return to the front desk, will lead to huge time difference, many times to perform the callback. So Laya do additional processing.

But egret.ticker egret use, when in the background, egret.ticker is the arrest, so do not deal with the difference in time huge problem.

class Timer {
        constructor(autoActive = true) {
            this.scale = 1;
            this.currTimer = Date.now();
            this.currFrame = 0;
            this._delta = 0;
            this._lastTimer = Date.now();
            this._map = [];
            this._handlers = [];
            this._temp = [];
            this._count = 0;
            autoActive && Timer.gSysTimer && Timer.gSysTimer.frameLoop(1, this, this._update);
        }
        get delta() {
            return this._delta;
        }
        _update() {
            if (this.scale <= 0) {
                this._lastTimer = Date.now();
                this._delta = 0;
                return;
            }
            var frame = this.currFrame = this.currFrame + this.scale;
            var now = Date.now();
            var awake = (now - this._lastTimer) > 30000;
            this._delta = (now - this._lastTimer) * this.scale;
            var timer = this.currTimer = this.currTimer + this._delta;
            this._lastTimer = now;
            var handlers = this._handlers;
            this._count = 0;
            for (var i = 0, n = handlers.length; i < n; i++) {
                var handler = handlers[i];
                if (handler.method !== null) {
                    was t = handler.userFrame? frame: hours; 
                    if (t >= handler.exeTime) {
                        if (handler.repeat) { 
                            if (! handler.jumpFrame || awake) { 
                                handler.exeTime + = handler.delay; 
                                handler.run (false); 
                                if (t> handler.exeTime) { 
                                    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 {
                    this._count++;
                }
            }
            if (this._count > 30 || frame % 200 === 0)
                this._clearHandlers();
        }
        _clearHandlers() {
            var handlers = this._handlers;
            for (var i = 0, n = handlers.length; i < n; i++) {
                var handler = handlers[i];
                if (handler.method !== null)
                    this._temp.push(handler);
                else
                    this._recoverHandler(handler);
            }
            this._handlers = this._temp;
            handlers.length = 0;
            this._temp = handlers;
        }
        _recoverHandler(handler) {
            if (this._map[handler.key] == handler)
                this._map[handler.key] = null;
            handler.clear();
            Timer._pool.push(handler);
        }
        _create(useFrame, repeat, delay, caller, method, args, coverBefore) {
            if (!delay) {
                method.apply(caller, args);
                return null;
            }
            if (coverBefore) {
                var handler = this._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 + Date.now() - this._lastTimer);
                    return handler;
                }
            }
            handler = Timer._pool.length > 0 ? Timer._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 + Date.now () - this._lastTimer); 
            this._indexHandler (trades); 
            this._handlers.push (trades); 
            return trades; 
        } 
        _IndexHandler (act) { 
            were Caller = handler.caller; 
            were method = handler.method; 
            was cid = caller? caller. $ _ GID || (caller. $ _ GID = ILaya.Utils.getGID ()): 0;
            was mid = method. $ _ TIME || (method. $ _ = TIME (Timer._mid ++) * 100000); 
            handler.key cid = mid +; 
            this._map [handler.key] = trades;
        }
        once(delay, caller, method, args = null, coverBefore = true) {
            this._create(false, false, delay, caller, method, args, coverBefore);
        }
        loop(delay, caller, method, args = null, coverBefore = true, jumpFrame = false) {
            var handler = this._create(false, true, delay, caller, method, args, coverBefore);
            if (handler)
                handler.jumpFrame = jumpFrame;
        }
        frameOnce(delay, caller, method, args = null, coverBefore = true) {
            this._create(true, false, delay, caller, method, args, coverBefore);
        }
        frameLoop(delay, caller, method, args = null, coverBefore = true) {
            this._create(true, true, delay, caller, method, args, coverBefore);
        }
        toString() {
            return " handlers:" + this._handlers.length + " pool:" + Timer._pool.length;
        }
        clear(caller, method) {
            var handler = this._getHandler(caller, method);
            if (handler) {
                this._map[handler.key] = null;
                handler.key = 0;
                handler.clear();
            }
        }
        clearAll(caller) {
            if (!caller)
                return;
            for (var i = 0, n = this._handlers.length; i < n; i++) {
                var handler = this._handlers[i];
                if (handler.caller === caller) {
                    this._map[handler.key] = null;
                    handler.key = 0;
                    handler.clear();
                }
            }
        }
        _getHandler(caller, method) {
            var cid = caller ? caller.$_GID || (caller.$_GID = ILaya.Utils.getGID()) : 0;
            var mid = method.$_TID || (method.$_TID = (Timer._mid++) * 100000);
            return this._map[cid + mid];
        }
        callLater(caller, method, args = null) {
            CallLater.I.callLater(caller, method, args);
        }
        runCallLater(caller, method) {
            CallLater.I.runCallLater(caller, method);
        }
        runTimer(caller, method) {
            var handler = this._getHandler(caller, method);
            if (handler && handler.method != null) {
                this._map[handler.key] = null;
                handler.run(true);
            }
        }
        pause() {
            this.scale = 0;
        }
        resume() {
            this.scale = 1;
        }
    }
    Timer.gSysTimer = null;
    Timer._pool = [];
    Timer._mid = 1;
    class TimerHandler {
        clear() {
            this.caller = null;
            this.method = null;
            this.args = null;
        }
        run(withClear) {
            var caller = this.caller;
            if (caller && caller.destroyed)
                return this.clear();
            var method = this.method;
            var args = this.args;
            withClear && this.clear();
            if (method == null)
                return;
            args ? method.apply(caller, args) : method.call(caller);
        }
    }

  

 

Guess you like

Origin www.cnblogs.com/gamedaybyday/p/11832645.html