first
This commit is contained in:
276
extensions/app/assets/manager/timer/TimerManager.ts
Normal file
276
extensions/app/assets/manager/timer/TimerManager.ts
Normal file
@@ -0,0 +1,276 @@
|
||||
import { _decorator } from 'cc';
|
||||
import BaseManager from '../../base/BaseManager';
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
type ICallback = (...args: any[]) => any;
|
||||
|
||||
class DailyTimer {
|
||||
// 获取当前时间相对于当日零点的毫秒数
|
||||
private static getDayTimeMs(date: Date): number {
|
||||
return (
|
||||
date.getHours() * 3600 +
|
||||
date.getMinutes() * 60 +
|
||||
date.getSeconds()
|
||||
) * 1000 + date.getMilliseconds();
|
||||
}
|
||||
|
||||
// 静态方法解析时间为毫秒数
|
||||
private static parseTimeToMs(h: number, m: number, s: number): number {
|
||||
return ((h * 3600 + m * 60 + s) * 1000) % 86400000;
|
||||
}
|
||||
|
||||
private readonly startMs: number; // 起始时间毫秒数(相对于当日零点)
|
||||
private readonly endMs: number; // 结束时间毫秒数
|
||||
|
||||
// 用于检查当前时间是否可触发回调
|
||||
private checkDay = 0;
|
||||
|
||||
constructor(
|
||||
time: string,
|
||||
public readonly callback: ICallback,
|
||||
public readonly target?: unknown,
|
||||
public readonly once: boolean = false
|
||||
) {
|
||||
// 使用解构赋值提高可读性
|
||||
const [startSegment, endSegment = startSegment] = time.split('-');
|
||||
|
||||
// 开始时间
|
||||
const [startH = 0, startM = 0, startS = 0] = startSegment.split(':').map(
|
||||
part => Math.max(0, parseInt(part, 10) || 0)
|
||||
);
|
||||
this.startMs = DailyTimer.parseTimeToMs(startH, startM, startS);
|
||||
|
||||
// 结束时间
|
||||
const [endH = 0, endM = 0, endS = 0] = endSegment.split(':').map(
|
||||
part => Math.max(0, parseInt(part, 10) || 0)
|
||||
);
|
||||
this.endMs = DailyTimer.parseTimeToMs(endH, endM, endS);
|
||||
// 结束时间与开始时间不能相同
|
||||
if (this.endMs === this.startMs) {
|
||||
if (startM === 0 && startS === 0) {
|
||||
this.endMs = DailyTimer.parseTimeToMs(startH + 1, startM, startS);
|
||||
} else if (startS === 0) {
|
||||
this.endMs = DailyTimer.parseTimeToMs(startH, startM + 1, startS);
|
||||
} else {
|
||||
this.endMs = DailyTimer.parseTimeToMs(startH, startM, startS + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前时间是否在时间范围内
|
||||
private isInRange(now: Date): boolean {
|
||||
const currentMs = DailyTimer.getDayTimeMs(now);
|
||||
|
||||
// 处理跨天时间段(如 23:00-01:00)
|
||||
return this.startMs <= this.endMs
|
||||
? currentMs >= this.startMs && currentMs < this.endMs
|
||||
: currentMs >= this.startMs || currentMs < this.endMs;
|
||||
}
|
||||
|
||||
update(now: Date): boolean {
|
||||
const dateDay = now.getDay();
|
||||
|
||||
if (this.checkDay === dateDay) return false;
|
||||
if (!this.isInRange(now)) return false;
|
||||
|
||||
this.checkDay = dateDay;
|
||||
this.callback.call(this.target);
|
||||
|
||||
return this.once;
|
||||
}
|
||||
}
|
||||
|
||||
class IntervalTimer {
|
||||
private elapsed: number = 0;
|
||||
|
||||
constructor(
|
||||
public readonly interval: number,
|
||||
public readonly callback: ICallback,
|
||||
public readonly target?: unknown,
|
||||
public readonly once: boolean = false
|
||||
) { }
|
||||
|
||||
update(dt: number): boolean {
|
||||
this.elapsed += dt;
|
||||
let completed = false;
|
||||
|
||||
// 处理可能多次触发的情况(当dt > interval时)
|
||||
while (this.elapsed >= this.interval) {
|
||||
this.callback.call(this.target);
|
||||
this.elapsed -= this.interval;
|
||||
|
||||
if (this.once) {
|
||||
completed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
|
||||
class Timer {
|
||||
static update(timer: Timer, dt: number) {
|
||||
return timer.update(dt);
|
||||
}
|
||||
|
||||
private intervalTimer: IntervalTimer[] = [];
|
||||
|
||||
/**
|
||||
* 注册定时器
|
||||
* @param interval
|
||||
* @param callback
|
||||
* @param target
|
||||
* @param once
|
||||
*/
|
||||
register(
|
||||
interval: number,
|
||||
callback: ICallback,
|
||||
target?: unknown,
|
||||
once?: boolean
|
||||
): void {
|
||||
const timer = new IntervalTimer(interval, callback, target, once || false);
|
||||
this.intervalTimer.push(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消定时器
|
||||
* @param callback
|
||||
* @param target
|
||||
*/
|
||||
unregister(callback: ICallback, target?: unknown): void {
|
||||
if (typeof target === 'undefined') {
|
||||
this.intervalTimer = this.intervalTimer.filter(
|
||||
timer => timer.callback !== callback
|
||||
);
|
||||
} else {
|
||||
this.intervalTimer = this.intervalTimer.filter(
|
||||
timer => !(timer.callback === callback && timer.target === target)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消所有定时器
|
||||
*/
|
||||
unregisterAll() {
|
||||
this.intervalTimer = [];
|
||||
}
|
||||
|
||||
private dailyTimers: DailyTimer[] = [];
|
||||
|
||||
/**
|
||||
* 注册每日触发器
|
||||
* @param time 24小时制,精确到秒
|
||||
*
|
||||
* @example
|
||||
* registerDailyTrigger('16', ...) 等同于 registerDailyTrigger('16-17', ...)
|
||||
* registerDailyTrigger('8-9:00', ...) 等同于 registerDailyTrigger('8', ...)
|
||||
* registerDailyTrigger('8:00:01-24', ...)
|
||||
*/
|
||||
registerDailyTrigger(
|
||||
time: string,
|
||||
callback: ICallback,
|
||||
target?: unknown,
|
||||
once?: boolean
|
||||
) {
|
||||
const timer = new DailyTimer(time, callback, target, once || false);
|
||||
this.dailyTimers.push(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消每日触发器
|
||||
*/
|
||||
unregisterDailyTrigger(callback: ICallback, target?: unknown) {
|
||||
if (typeof target === 'undefined') {
|
||||
this.dailyTimers = this.dailyTimers.filter(
|
||||
timer => timer.callback !== callback
|
||||
);
|
||||
} else {
|
||||
this.dailyTimers = this.dailyTimers.filter(
|
||||
timer => !(timer.callback === callback && timer.target === target)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消所有每日触发器
|
||||
*/
|
||||
unregisterAllDailyTrigger() {
|
||||
this.dailyTimers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有定时器和触发器
|
||||
*/
|
||||
clear() {
|
||||
this.intervalTimer = [];
|
||||
this.dailyTimers = [];
|
||||
}
|
||||
|
||||
protected update(dt: number): void {
|
||||
for (let index = 0; index < this.intervalTimer.length; index++) {
|
||||
const timer = this.intervalTimer[index];
|
||||
if (timer.update(dt)) {
|
||||
this.intervalTimer.splice(index, 1);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
const date = new Date();
|
||||
for (let index = 0; index < this.dailyTimers.length; index++) {
|
||||
const timer = this.dailyTimers[index];
|
||||
if (timer.update(date)) {
|
||||
this.dailyTimers.splice(index, 1);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ccclass('TimerManager')
|
||||
export default class TimerManager extends BaseManager {
|
||||
private timers: Map<string | number | Symbol, Timer> = new Map();
|
||||
|
||||
/**
|
||||
* 清除所有定时器
|
||||
*/
|
||||
clear() {
|
||||
this.timers.forEach((timer) => {
|
||||
timer.clear();
|
||||
});
|
||||
this.timers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除定时器
|
||||
* @param key 定时器key
|
||||
*/
|
||||
delete(key: string | number | Symbol) {
|
||||
const timer = this.timers.get(key);
|
||||
if (!timer) return;
|
||||
|
||||
this.timers.delete(key);
|
||||
timer.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时器
|
||||
* @param key 定时器key
|
||||
*/
|
||||
get(key: string | number | Symbol): Timer {
|
||||
if (this.timers.has(key)) {
|
||||
return this.timers.get(key);
|
||||
}
|
||||
|
||||
const timer = new Timer();
|
||||
this.timers.set(key, timer);
|
||||
return timer;
|
||||
}
|
||||
|
||||
protected update(dt: number): void {
|
||||
this.timers.forEach((timer) => {
|
||||
Timer.update(timer, dt);
|
||||
});
|
||||
}
|
||||
}
|
||||
9
extensions/app/assets/manager/timer/TimerManager.ts.meta
Normal file
9
extensions/app/assets/manager/timer/TimerManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "b5636f8d-3516-4510-aaba-74f9202b8a9f",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
Reference in New Issue
Block a user