Egret自定義計時器(TimerManager和Laya.timer)


 

一 自定義計時器

因為游戲中經常用到計時器,比如每1秒發射一枚子彈啊,每2秒怪物AI自動轉向啊

每次去new Timer 然后addEventListener(egret.TimerEvent...     之類的太麻煩了。

 

所以自定義一個計時器

 

二  決戰沙城的自定義計時器

來看看決戰沙城的自定義計時器

原理就是egret.Ticker每幀執行,讓列表里TimerHandler加上時間或幀,檢查當到了計時時間結束時,就執行回調。

/**
 * 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);

        //創建
        var handler: 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++;
    }

    /**
     * 在指定的延遲(以毫秒為單位)后運行指定的函數。
     * @param delay 執行間隔:毫秒
     * @param method 執行函數
     * @param methodObj 執行函數所屬對象
     */
    public setTimeOut(delay: number, method: Function, methodObj: any): void {
        this.doTimer(delay, 1, method, methodObj);
    }

    /**
     * 在指定的幀后運行指定的函數。
     * @param delay 執行間隔:幀頻
     * @param method 執行函數
     * @param methodObj 執行函數所屬對象
     */
    public setFrameOut(delay: number, method: Function, methodObj: any): void {
        this.doFrame(delay, 1, method, methodObj);
    }

    /**
     *
     * 定時執行
     * @param delay 執行間隔:毫秒
     * @param repeatCount 執行次數, 0為無限次
     * @param method 執行函數
     * @param methodObj 執行函數所屬對象
     * @param complateMethod 完成執行函數
     * @param complateMethodObj 完成執行函數所屬對象
     *
     */
    public doTimer(delay: number, repeatCount: number, method: Function, methodObj: any, complateMethod: Function = null, complateMethodObj: any = null): void {
        this.create(false, delay, repeatCount, method, methodObj, complateMethod, complateMethodObj);
    }

    /**
     *
     * 定時執行
     * @param delay 執行間隔:幀頻
     * @param repeatCount 執行次數, 0為無限次
     * @param method 執行函數
     * @param methodObj 執行函數所屬對象
     * @param complateMethod 完成執行函數
     * @param complateMethodObj 完成執行函數所屬對象
     *
     */
    public doFrame(delay: number, repeatCount: number, method: Function, methodObj: any, complateMethod: Function = null, complateMethodObj: any = null): void {
        this.create(true, delay, repeatCount, method, methodObj, complateMethod, complateMethodObj);
    }

    /**
     * 定時器執行數量
     * @return
     *
     */
    public get count(): number {
        return this._count;
    }

    /**
     * 清理
     * @param method 要移除的函數
     * @param methodObj 要移除的函數對應的對象
     */
    public remove(method: Function, methodObj: any): void {
        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) {
                this._delHandlers.push(handler);
                break;
            }
        }
    }

    /**
     * 清理
     * @param methodObj 要移除的函數對應的對象
     */
    public removeAll(methodObj: 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);
            }
        }
    }

    /**
     * 檢測是否已經存在
     * @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;
            }
        }
    }
}


class TimerHandler {
    /**執行間隔*/
    public delay: number = 0;
    /**是否重復執行*/
    public repeat: boolean;
    /**重復執行次數*/
    public repeatCount: number = 0;
    /**是否用幀率*/
    public userFrame: boolean;
    /**執行時間*/
    public exeTime: number = 0;
    /**處理函數*/
    public method: Function;
    /**處理函數所屬對象*/
    public methodObj: any;
    /**完成處理函數*/
    public complateMethod: Function;
    /**完成處理函數所屬對象*/
    public complateMethodObj: any;
    /**上次的執行時間*/
    public dealTime: number = 0;

    /**清理*/
    public clear(): void {
        this.method = null;
        this.methodObj = null;
        this.complateMethod = null;
        this.complateMethodObj = null;
    }
}

  

三  Laya的timer

laya已經提供了一個timer給開發者使用,功能和決戰沙城的差不多

 由於Laya用的Date.now,那么在游戲置於后台過久,再返回前台時,會導致時間相差巨大,執行很多次回調。所以Laya做了額外處理。

但是egret使用的egret.ticker,置於后台時,egret.ticker是停跳了的,所以不用處理時間相差巨大的問題。

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) {
                    var t = handler.userFrame ? frame : timer;
                    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(handler);
            this._handlers.push(handler);
            return handler;
        }
        _indexHandler(handler) {
            var caller = handler.caller;
            var method = handler.method;
            var cid = caller ? caller.$_GID || (caller.$_GID = ILaya.Utils.getGID()) : 0;
            var mid = method.$_TID || (method.$_TID = (Timer._mid++) * 100000);
            handler.key = cid + mid;
            this._map[handler.key] = handler;
        }
        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);
        }
    }

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM