一, 代码核心
1,CommonTimer.ts
/**
* 通用计时器
*/
import {CommonTimerModeType, ICommonTimerInfo} from "./CommomTimerDefine";
export default class CommonTimerMgr extends cc.Component {
public static instance: CommonTimerMgr;
private timerList: ICommonTimerParam[];
/**ms*/
private localTime: number;
private deleteList: ICommonTimerParam[];
protected onl oad(): void {
if (!CommonTimerMgr.instance) {
this.init();
CommonTimerMgr.instance = this;
} else {
CC_DEBUG && console.log(`[Fishdom] %cCommonTimerMgr 为单例类`, "color:#F00");
this.destroy();
}
}
private init(): void {
this.timerList = [];
this.deleteList = [];
this.resetLocalTimer();
}
private resetIsExecOnceTrue(timerParam: ICommonTimerParam): void {
if (!timerParam) return;
!timerParam.isExecOnce && timerParam.isExecOnceMust && (timerParam.isExecOnce = true);
}
private addItemInfo(timerInfo: ICommonTimerInfo): void {
let timerParam: ICommonTimerParam = timerInfo;
if (timerInfo.repeat == undefined) {
timerInfo.repeat = 1;
}
if (!timerParam.mode) {
timerParam.mode = CommonTimerModeType.TIMER;
}
timerParam.isExecOnce = false;
if (timerParam.mode == CommonTimerModeType.TIMER) {
if (timerParam.isInitExec) {
timerParam.callback.call(
timerParam.target,
timerParam.flag,
timerParam.duration,
false,
timerParam.callbackParam
);
this.resetIsExecOnceTrue(timerParam);
}
timerParam.startTime = this.localTime;
}
timerParam.curExecCnt = 0;
this.timerList.push(timerParam);
}
/**
* 添加一个计时器
*/
public addTimer(data: ICommonTimerInfo): void {
if (!cc.isValid(this.node)) return;
if (!data || !data.callback || !data.target || !data.flag) {
CC_DEBUG && console.log(`[Fishdom] %c Error添加计时器出错!`, "color:#F00");
return;
}
if (CC_BUILD && data.flag.trim().length <= 0) {
CC_DEBUG && console.log(`[Fishdom] %c Error 添加计时器flag参数不能为空!`, "color:#F00");
return;
}
if (this.timerList.length == 0) {
this.localTime = 0;
this.addItemInfo(data);
} else {
let timerParam: ICommonTimerParam;
for (let i: number = 0; i < this.timerList.length; i++) {
timerParam = this.timerList[i];
if (timerParam.flag == data.flag) {
this.doMuskExecFinal(timerParam);
this.timerList.splice(i, 1);
break;
}
}
this.addItemInfo(data);
}
}
private doMuskExecFinal(timerParam: ICommonTimerParam): void {
if (!timerParam) return;
if (!timerParam.isExecOnceMust || timerParam.isExecOnce) return;
timerParam.callback.call(
timerParam.target,
timerParam.flag,
timerParam.duration,
true,
timerParam.callbackParam
);
}
/**
* 删除计时器
* @param flag null: 删除所有计时器(清空)
* @param isCheckExecCnt 是否需要检查执行的次数
*/
public removeTimer(flag: string, isCheckExecCnt: boolean = false): void {
if (!this.timerList || this.timerList.length == 0) return;
let itemTimer: ICommonTimerParam;
for (let i: number = 0, j: number = this.timerList.length; i < j; i++) {
itemTimer = this.timerList[i];
if (flag != null && flag.trim().length > 0) {
if (itemTimer.flag == flag) {
if (!isCheckExecCnt || itemTimer.repeat <= 0) {
this.doMuskExecFinal(itemTimer);
this.timerList.splice(i, 1);
} else {
if (itemTimer.curExecCnt >= itemTimer.repeat) {
this.doMuskExecFinal(itemTimer);
this.timerList.splice(i, 1);
}
}
break;
}
} else if (flag == null || flag.trim().length <= 0) {
itemTimer = this.timerList[i];
this.doMuskExecFinal(itemTimer);
this.timerList.splice(i, 1);
i--;
j--;
}
}
this.resetLocalTimer();
}
protected update(dt: number): void {
if (!this.timerList || this.timerList.length <= 0) return;
this.onTimerHandler.call(this, dt * 1000);
}
private onTimerHandler: (msDt: number) => void = (msDt) => {
this.localTime += msDt;
let itemTimer: ICommonTimerParam;
let cloneArr: ICommonTimerParam[] = this.shallowCloneTimerList(this.timerList);
if (cloneArr == null || cloneArr.length <= 0) {
this.resetLocalTimer();
return;
}
let asyncHandler: Promise<void>[] = [];
for (let i: number = 0, j: number = cloneArr.length; i < j; i++) {
itemTimer = this.timerList[i];
asyncHandler.push(this.doTimerAsync(itemTimer, i, msDt));
}
Promise.all(asyncHandler).then(() => {
if (
!this.deleteList ||
this.deleteList.length == 0 ||
!this.timerList ||
this.timerList.length == 0
) {
this.resetLocalTimer();
return;
}
let deleteArr: ICommonTimerParam[] = this.shallowCloneTimerList(this.deleteList);
if (deleteArr != null && deleteArr.length > 0) {
let item: ICommonTimerParam;
for (let i: number = 0; i < deleteArr.length; i++) {
item = deleteArr[i];
this.removeTimer(item.flag, true);
}
}
this.resetLocalTimer();
});
};
private async doTimerAsync(
itemTimer: ICommonTimerParam,
i: number,
msDt: number
): Promise<void> {
return new Promise<void>((resolve) => {
if (i == 0) this.deleteList.length = 0;
if (itemTimer.mode == CommonTimerModeType.TIMER) {
if (this.localTime - itemTimer.startTime < itemTimer.duration) {
resolve();
return;
}
if (itemTimer.repeat != null && itemTimer.repeat > 0) {
//非永久执行
itemTimer.curExecCnt += 1;
if (itemTimer.curExecCnt >= itemTimer.repeat) {
if (itemTimer.curExecCnt == itemTimer.repeat)
itemTimer.callback.call(
itemTimer.target,
itemTimer.flag,
itemTimer.duration,
true,
itemTimer.callbackParam
);
this.deleteList.push(itemTimer);
this.resetIsExecOnceTrue(itemTimer);
} else {
itemTimer.startTime = this.localTime;
itemTimer.callback.call(
itemTimer.target,
itemTimer.flag,
itemTimer.duration,
false,
itemTimer.callbackParam
);
this.resetIsExecOnceTrue(itemTimer);
}
} else {
itemTimer.startTime = this.localTime;
itemTimer.callback.call(
itemTimer.target,
itemTimer.flag,
itemTimer.duration,
false,
itemTimer.callbackParam
); //永久执行
this.resetIsExecOnceTrue(itemTimer);
}
} else if (itemTimer.mode == CommonTimerModeType.FRAME) {
//非永久执行
if (itemTimer.repeat != null && itemTimer.repeat > 0) {
itemTimer.curExecCnt += 1;
if (itemTimer.curExecCnt >= itemTimer.repeat) {
if (itemTimer.curExecCnt == itemTimer.repeat)
itemTimer.callback.call(
itemTimer.target,
itemTimer.flag,
msDt,
true,
itemTimer.callbackParam
);
this.deleteList.push(itemTimer);
this.resetIsExecOnceTrue(itemTimer);
} else {
itemTimer.callback.call(
itemTimer.target,
itemTimer.flag,
msDt,
false,
itemTimer.callbackParam
);
this.resetIsExecOnceTrue(itemTimer);
}
} else {
itemTimer.callback.call(
itemTimer.target,
itemTimer.flag,
msDt,
false,
itemTimer.callbackParam
); //永久执行
this.resetIsExecOnceTrue(itemTimer);
}
}
resolve();
});
}
private shallowCloneTimerList(list: ICommonTimerParam[]): ICommonTimerParam[] {
if (list == null || list.length <= 0) return null;
let arr: ICommonTimerParam[] = [];
for (let i: number = 0; i < list.length; i++) {
arr.push(list[i]);
}
return arr;
}
/**通用起点归0处理*/
private resetLocalTimer(): void {
if (this.timerList.length == 0) {
this.localTime = 0;
} else {
let itemTimer: ICommonTimerParam;
for (let i: number = 0; i < this.timerList.length; i++) {
itemTimer = this.timerList[i];
if (itemTimer.mode == CommonTimerModeType.TIMER) {
return; //存在时间计时器,不予处理
}
}
this.localTime = 0;
}
}
/**
* 销毁计时器
*/
public destroyTimer(): void {
if (CommonTimerMgr.instance) {
if (CommonTimerMgr.instance.node) {
CommonTimerMgr.instance.node.removeComponent(this);
}
this.timerList = null;
this.deleteList = null;
CommonTimerMgr.instance = null;
}
}
}
interface ICommonTimerParam extends ICommonTimerInfo {
/**已经执行的次数*/
curExecCnt?: number;
/**开始的时间毫秒(ms)*/
startTime?: number;
/**是否已经执行过一次(初次执行也算)*/
isExecOnce?: boolean;
}
2, CommonTimerMgr
/**
* 时间计时类型
*/
export const enum CommonTimerModeType {
/**时间*/
TIMER = "timer",
/**帧*/
FRAME = "frame",
}
/**
* 计时器数据
*/
export interface ICommonTimerInfo {
/**计时器唯一标签,作为计时器的key*/
flag: string;
/**计时器模式:默认: CommonTimerModeType.TIMER*/
mode?: CommonTimerModeType;
/**执行次数 <=0 : 永久执行 默认: 1次*/
repeat?: number;
/**是否初始化先执行一次(只对TIMER模式有效) 默认:false*/
isInitExec?: boolean;
/**回调函数 isComplete: 是否为结束回调*/
callback: (flag: string, dt?: number, isComplete?: boolean, param?: any) => void;
/**回调函数 This*/
target: any;
/**间隔时间毫秒(ms):(只对TIMER模式有效) */
duration?: number;
/**回调至少要执行一次?防止强制清理计时器,导致必要的动作没有执行:比如请求加分,默认false*/
isExecOnceMust?: boolean;
/**回调参数*/
callbackParam?: any;
}
二,使用
1, 挂载到节点
this.node.addComponent(CommonTimerMgr);
2, 使用
private addTimer(): void{
CommonTimerMgr.instance.addTimer({
flag: "timer_common",
mode: CommonTimerModeType.TIMER,
callback: this.onTimerHandler,
target: this,
duration: 1000,
callbackParam: "demo param",
repeat: 3
});
}
private onTimerHandler(flag: string, dt: number, isComplete: boolean, data: any): void{
switch (flag){
case "timer_common":
cc.log(`得到的参数: ${data}`);
break;
}
}
/**删除timer_common计时器*/
private removeTime(): void{
CommonTimerMgr.instance.removeTimer("timer_common");
}