Timer
The GameTimer provides pause-aware timing primitives for game logic. It offers one-shot delays, repeating intervals, and pollable cooldowns -- all operating in game-time milliseconds derived from the engine's delta time.
When the game is paused, all timers freeze automatically.
Accessing the Timer
const engine = await createGameEngine(canvas, entityClasses);
const timer = engine.timer;The timer is engine-side, ticked once a rendered frame by a frame callback. It is not part of the entity system: a behavior does not reach it, and its callbacks run outside the fixed step.
API Reference
| Method | Signature | Returns | Description |
|---|---|---|---|
delay | (ms : number, callback : () => void) | () => void | One-shot timer; returns a cancel function |
interval | (ms : number, callback : () => void) | () => void | Repeating timer; returns a cancel function |
cooldown | (ms : number) | CooldownHandle | Pollable cooldown handle |
cancelAll | () | void | Cancel all active delays, intervals, and cooldowns |
delay
Fires a callback once after ms milliseconds of game time. Returns a cancel function.
showHitIndicator();
const cancel = engine.timer.delay(200, () =>
{
hideHitIndicator();
});
// Changed your mind? Cancel it.
cancel();The ms parameter must be >= 0. Passing a negative value throws a RangeError.
interval
Fires a callback repeatedly every ms milliseconds of game time. Returns a cancel function.
// Regenerate 1 HP every 2 seconds
const cancel = engine.timer.interval(2000, () =>
{
player.state.hp = Math.min(player.state.hp + 1, player.state.maxHp);
});
// Stop regeneration
cancel();The ms parameter must be > 0 (strictly positive). Passing zero or a negative value throws a RangeError.
WARNING
An interval of 0 is not allowed because it would fire infinitely within a single frame. Use delay(0, ...) for a next-frame callback instead.
cooldown
Creates a pollable cooldown handle. Starts in the ready state. After calling reset(), the cooldown becomes not-ready until ms milliseconds of game time have elapsed.
const fireCooldown = engine.timer.cooldown(500);
function tryShoot() : void
{
if(fireCooldown.ready)
{
shootProjectile();
fireCooldown.reset(); // Starts the 500ms cooldown
}
}CooldownHandle
interface CooldownHandle
{
readonly ready : boolean;
reset() : void;
}| Property / Method | Type | Description |
|---|---|---|
ready | boolean | true when the cooldown has elapsed (or has never been reset) |
reset() | () => void | Start (or restart) the cooldown timer |
Cooldowns are passive -- they do not fire callbacks. Check ready whenever you need to gate an action. This makes them ideal for ability cooldowns, rate-limiting player actions, or any "can I do this yet?" check.
cancelAll
Clears all active delays, intervals, and cooldowns:
engine.timer.cancelAll();Nothing calls this for you. A game that wants its timers cleared on a level transition calls it from the transition.
Any CooldownHandle references you are still holding will report ready: true after cancelAll() is called.
Game Time vs. Wall Time
All durations are measured in game-time milliseconds. The timer advances by the engine's delta time each frame via an internal tick(dtMs) call. Key consequences:
| Behavior | Detail |
|---|---|
| Pausing freezes all timers | When the game is paused, tick() is not called -- delays, intervals, and cooldowns all freeze |
| Frame rate affects granularity | A 500ms delay fires on the first frame where accumulated time >= 500ms. At 60fps (~16.7ms/frame), that is within one frame of accuracy. |
| No built-in time scale | There is no time multiplier. Slow-motion or fast-forward would need to be implemented at the engine loop level. |
Usage Patterns
Timed Power-Up
function activateShield(player : PlayerEntity) : void
{
player.emit('action:shield', { active: true }, player.id);
engine.timer.delay(5000, () =>
{
player.emit('action:shield', { active: false }, player.id);
});
}The callback lands between fixed steps, so it emits an event for the entity's own behavior to apply at the next drain rather than writing the entity's state from outside.
Spawn Wave Timer
let wave = 0;
const cancelWaves = engine.timer.interval(10000, () =>
{
wave++;
spawnEnemyWave(wave);
if(wave >= maxWaves)
{
cancelWaves();
}
});Rate-Limited Action
const dashCooldown = engine.timer.cooldown(3000);
let dashesHandled = 0;
engine.managers.gameManager.registerFrameCallback(() =>
{
if(player.state.dashRequested > dashesHandled && dashCooldown.ready)
{
performDash();
dashCooldown.reset();
}
dashesHandled = player.state.dashRequested;
});Here dashRequested is a counter a behavior increments on each action:dash event, and the frame callback polls it after the fixed step has run.
