import { HZEngineCore, Storage } from "../index.js"; import { Save } from "../storage/decorator.js"; import { ZeppTimer } from "./zeppos_timer.js"; // import { Time } from "@zos/sensor"; export class Async { static _nextTickCallbacks: (() => void)[] = []; static _nextTickTimerId: number | null = null; static nextTick(callback: () => void) { this._nextTickCallbacks.push(callback); if (this._nextTickTimerId == null) { this._nextTickTimerId = setTimeout(() => { this._nextTickTimerCallback(); }, 30) as unknown as number; } } static _nextTickTimerCallback() { this._nextTickTimerId = null; const callbacks = this._nextTickCallbacks; this._nextTickCallbacks = []; callbacks.forEach((cb) => { cb(); }); } // private _fps = 45; // private _hmTime = new Time(); private _lastTime: number; constructor(public _core: HZEngineCore) { // console.log("async init"); // let timer = new ZeppTimer(() => { // // console.log(`async timer cb`); // this._scheduleTask(); // }, ~~(1000 / this._fps)); // timer.start(); this._lastTime = this._core.platform.getTime(); // setInterval(() => { // this._scheduleTask(); // }, ~~(1000 / this._fps)); _core.platform.setFrameInterval(() => { this._scheduleTask(); }); } _scheduleTask() { // TODO 沒有充分考慮存檔時產生的問題(this._delayTasks引用變化),及其它問題 let now = this._core.platform.getTime(); let deltaTime = now - this._lastTime; this._lastTime = now; // console.log(`async timer cb d=${deltaTime}`); for (let id in this._delayTasks) { let task = this._delayTasks[id]; task.next -= deltaTime; if (task.next <= 0) { this._core.emit(task.event, ...task.args); if (task.repeat >= 0) { // interval task.next += task.repeat; } else { delete this._delayTasks[id]; } } } } @Save("async.nextTimerId") private accessor _nextTimerId: number = 50; // tasks @Save("async.delayTasks") private accessor _delayTasks: Record = {}; // 注意在task執行中立即創建一個新的task,會在同一個js task中執行 // 注意周期實際為1個frame的時間的整數倍 addDelayTask( event: string, args: Storage.Saveable[], delayMs: number ): number { let task: Async.Task = { event, args, next: delayMs, repeat: -1, }; let id = this._nextTimerId++; this._delayTasks[id] = task; return id; } addRepeatTask( event: string, args: Storage.Saveable[], intervalMs: number, delayMs?: number ): number { intervalMs = intervalMs >= 0 ? intervalMs : 0; let task: Async.Task = { event, args, next: delayMs ?? intervalMs, repeat: intervalMs, }; let id = this._nextTimerId++; this._delayTasks[id] = task; return id; } removeTask(id: number) { delete this._delayTasks[id]; } } export namespace Async { export interface Task { event: string; args: Storage.Saveable[]; next: number; // remaining time in ms repeat: number; // -1 for once ; >=0 for repeat circle } }