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);
}
}
Egret自定义计时器(TimerManager和Laya.timer)的更多相关文章
- Laya Timer原理 & 源码解析
Laya Timer原理 & 源码解析 @author ixenos 2019-03-18 16:26:38 一.原理 1.将所有Handler注册到池中 1.普通Handler在handle ...
- Egret自定义位图文字(自定义+BitmapLabel)
一 自定位图文字 因为egret的位图文字是texturemerger做的,需要多张单图片导入tm,然后导出两个文件来使用,过程比较麻烦. 而Laya的位图文字则是一张整图数字图片,使用FontCli ...
- Egret 纹理、计时器
1. 九宫切 典型例子就是圆角矩形的拉伸问题. 先去P一张绿色的圆角矩形. private createGameScene():void { var box:egret.Bitmap = new eg ...
- C#中自定义高精度Timer定时器的实例教程
Timer 用于以用户定义的事件间隔触发事件.Windows 计时器是为单线程环境设计的,其中,UI 线程用于执行处理.它要求用户代码有一个可用的 UI 消息泵,而且总是在同一个线程中操作,或者将调用 ...
- 线程 Timer TimerTask 计时器 定时任务 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 【C#/WPF】用System.Timers.Timer计时器做浮窗广告
需求:鼠标静止一段时间后,显示浮窗广告. 思路:界面XAML写好一个专门显示浮窗广告的Canvas,先设为不可见Visibility=”Collapsed”,然后用System.Timers.Time ...
- Laya资源加载小记
Laya.Loader负责资源的加载逻辑,被LoaderManager管理. Laya支持多种类型资源加载,也支持自定义类型加载.不同类型的加载方式可能不同. Laya.Loader缓存已经被加载过得 ...
- Java线程之Timer
简述 java.util.Timer是一个定时器,用来调度线程在某个时间执行.在初始化Timer时,开启一个线程循环提取TaskQueue任务数组中的任务, 如果任务数组为空,线程等待直到添加任务: ...
- Java基础--定时任务Timer
Java基础--定时任务Timer 一.Timer介绍 java.util.Timer java.util.TimerTask Timer是一个定时器类,通过该类可以为指定的定时任务进行配置.Time ...
随机推荐
- Jenkins中如何实现debug配置
java -jar -Xmx512m -Dfile.encoding=UTF-8 -server -XX:-OmitStackTraceInFastThrow -server -agentlib:jd ...
- sourceinsight sublimetext主题色配置
1.sourceinsight发布了4.0版本,全面支持了utf-8编码,这里sourinsight 颜色基本完全按照sublime默认的monokia主题来进行调色,效果如下图所示. 2.配色文件和 ...
- DFS 算法模板
dfs算法模板: 1.下一层是多节点的dfs遍历 def dfs(array or root, cur_layer, path, result): if cur_layer == len(array) ...
- python正则表达式(5)--findall、finditer方法
findall方法 相比其他方法,findall方法有些特殊.它的作用是查找字符串中所有能匹配的字符串,并以结果存于列表中,然后返回该列表 注意: match 和 search 是匹配一次 finda ...
- discuz x3.3门户出现关键词和描述显示“首页”的解决方法
Discuz社区在后台设置好门户标题.关键字.描述,更新缓存,发现用户登录状态下,门户首页的关键字和描述正常显示:但在游客状态下不显示,在某工具中查看到的情况是只显示首页,这对SEO是致命打击. 找到 ...
- Linux内核Socket实现之------Socket创建(2) 文件描述符
转载请注明:http://blog.chinaunix.net/uid-20788636-id-4408276.html 1.2 sock_map_fd函数 在用户空间创建了一个socket后,返回值 ...
- micronaut 学习 二 创建一个简单的服务
micronaut 提供的cli 很方便,我们可以快速创建具有所需特性的应用,以下是一个简单的web server app 创建命令 mn create-app hello-world 效果 mn c ...
- 【JZOJ6245】【20190627】A
题目 给定一颗\(n\)个点的树,边权为1,并给出\(\{w_i\}\)满足\(w_0=0\) \[ f(i) = \sum_{j=1}^{n} w_{dis(i,j)} \] 依次输出每一个\(f_ ...
- GitBook github
创建一个新的仓库 创建一个新文件,名为SUMMARY.md 创建一本书首先进入gitbook的官网:https://www.gitbook.com/ 创建账户https://github.com/ 在 ...
- nginx 访问控制之 user_agent
user_agent大家并不陌生,可以简单理解成浏览器标识,包括一些蜘蛛爬虫都可以通过user_agent来辨识. 通过访问日志,可以发现一些搜索引擎的蜘蛛对网站访问特别频繁,它们并不友好. 为了减少 ...