一 自定义计时器
因为游戏中经常用到计时器,比如每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);
- }
- }


