new animation, refactor, fixes

This commit is contained in:
Vasyl Kazakov
2026-06-18 12:45:48 +03:00
parent 930ed00c95
commit 852e1ec963
22 changed files with 519 additions and 116 deletions
+63
View File
@@ -0,0 +1,63 @@
import { Delegate, UpdateController } from "@24tools/playable_template";
export type ScheduledCall = {
remaining: number;
callback: () => void;
cancelled: boolean;
};
/**
* Відкладені виклики, керовані ігровим тікером (delta з `UpdateController`),
* а не `window.setTimeout`. Перевага: затримки можна скасувати на teardown і
* вони не спрацюють після завершення playable.
*
* Прим.: коли дійде черга до уніфікації часу (план, п.2) — масштаб `TimeC.TimeScale`
* додається саме тут, в одному місці.
*/
export class TickScheduler {
private static updateDelegate: Delegate<number> | null = null;
private static calls = new Set<ScheduledCall>();
/** `delaySeconds` — затримка в секундах ігрового часу. */
static schedule(delaySeconds: number, callback: () => void): ScheduledCall {
this.ensureUpdate();
const call: ScheduledCall = {
remaining: delaySeconds,
callback,
cancelled: false,
};
this.calls.add(call);
return call;
}
static cancel(call: ScheduledCall | null | undefined) {
if (!call) return;
call.cancelled = true;
this.calls.delete(call);
}
private static ensureUpdate() {
if (this.updateDelegate) return;
this.updateDelegate = UpdateController.Instance.onUpdate.addDelegate((delta) =>
this.update(delta),
);
}
private static update(delta: number) {
if (this.calls.size === 0) return;
for (const call of [...this.calls]) {
if (call.cancelled) {
this.calls.delete(call);
continue;
}
call.remaining -= delta;
if (call.remaining <= 0) {
this.calls.delete(call);
call.callback();
}
}
}
}