engine/Scheduler.ts は時間ベースの関数実行を担当します。GameLoop の dt を受け取り、内部に積んだタスクの remaining 時間を減算し、0 を下回ったタイミングで実行します。
タスクモデル#
type SchedulerTask = {
id: string;
callback: () => void;
remaining: number;
interval: number;
repeat: boolean;
};wait(delay, callback)は一度だけ実行するタスクを登録。schedule(callback, interval, { repeat })はデフォルトで繰り返し(repeat: true)。cancel(id)/clear()で後始末。
Game.update が Scheduler を World より先に呼び出すため、タスク内で Entity の状態を変更しても同じ tick 内で描画に反映されます。
使い所#
- HUD へ定期的にログを出す(
components/game-canvas.tsx内参照)。 - Cutscene のように「数秒待ってから次アクション」を表現する。
- Entity 内から
this.game.wait()を呼びたい場合は依存注入で Game インスタンスを受け取り、_ready()でタスク登録・_onExitWorld()でcancelTask()する。
エラーハンドリング#
タスク実行中に例外が起こっても Scheduler 自身は落ちません。console.warn() を出した上で、単発タスクは削除、繰り返しタスクは次のインターバルへ進みます。長時間走り続けるサービスを意識し、repeat タスクでは必ず cancel() のタイミングを決めておきましょう。
パフォーマンスのコツ#
- タスク数は
Mapで管理しているため数百件程度までなら問題なし。大量登録が必要ならgetTaskCount()を監視し、デバッグ HUD から過剰登録を検知する仕組みを追加すると安全です。 update(dt)はタスクが無い場合 O(1) で即 return するため、必要なタイミングでこまめにcancel()しておくと無駄なループを避けられます。