• 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);
            }
        }
    

      

  • 相关阅读:
    上传项目到github上
    app widget设置bitmap时,无作用
    Android Studio 启动app 白屏
    android sqlite 数据库中使用的类型
    android 解决华为系列手机调试时不能打印Logcat日志信息
    android 自定义滚动条图标
    检测邮箱
    js检测是否存在中文
    表单的checkbox选中和取消
    javascript
  • 原文地址:https://www.cnblogs.com/gamedaybyday/p/11832645.html
Copyright © 2020-2023  润新知