Skip to main content

Clock

The Excalibur mainloop, the infinite update and draw cycle, is driven by the Clock.

Standard clock

The standard clock is the default, and runs continuously once started. The internal implementation uses the browser requestAnimationFrame() to drive each game tick.

Limiting FPS

The FPS of the clock can be artificially limited in the Engine constructor, this can be useful to produce a consistent experience on many platforms or testing lower a framerate.

If no max is set, the FPS will be whatever the browser allows (usually display refresh rate)

For example, limiting to 30fps:

ts
const exampleGame = new ex.Engine({
maxFps: 30
});
ts
const exampleGame = new ex.Engine({
maxFps: 30
});

Scheduling tasks (also see Timer)

Instead of using the browser setTimeout() the clock can be used to schedule tasks that are tied to the Excalibur clock using Clock.schedule. This means they will respect when a game is stopped and not fire scheduled tasks.

ts
game.clock.schedule(() => {
console.log('Hello in 300ms');
}, 300);
ts
game.clock.schedule(() => {
console.log('Hello in 300ms');
}, 300);

Clearing scheduled tasks

You can also cancel scheduled tasks by saving the ID returned from schedule and passing it to clearSchedule:

ts
const taskId = game.clock.schedule(() => {
console.log('This will never be logged');
}, 500);
 
// Cancel the scheduled task
game.clock.clearSchedule(taskId);
ts
const taskId = game.clock.schedule(() => {
console.log('This will never be logged');
}, 500);
 
// Cancel the scheduled task
game.clock.clearSchedule(taskId);

Timing parameter

The schedule method accepts an ScheduledCallbackTiming enum an optional third parameter that specifies when in the game loop the callback should execute. This allows precise control over when your scheduled tasks run relative to the game's update cycle.

ts
// Schedule a callback to run before the frame is processed (default)
game.clock.schedule(() => {
console.log('Running before the frame');
}, 200, 'preframe');
 
// Schedule a callback to run after the frame is processed
game.clock.schedule(() => {
console.log('Running after the frame');
}, 200, 'postframe');
ts
// Schedule a callback to run before the frame is processed (default)
game.clock.schedule(() => {
console.log('Running before the frame');
}, 200, 'preframe');
 
// Schedule a callback to run after the frame is processed
game.clock.schedule(() => {
console.log('Running after the frame');
}, 200, 'postframe');

Available timing options:

  • 'preframe' (default): Executes before the frame update and draw cycle
  • 'postframe': Executes after the frame update and draw cycle
  • 'preupdate': Executes before the update logic
  • 'postupdate': Executes after the update logic
  • 'predraw': Executes before drawing
  • 'postdraw': Executes after drawing

Test clock

The test clock allows single stepping of each clock tick, which can be useful for debugging and unit testing.

Stepping & Running the clock

ts
const testClock = game.debug.useTestClock();
 
// Single Step as if we are running 60fps
testClock.step(16.6);
 
// Multiple steps at once, for example 100 steps at 60fps
testClock.run(100, 16.6);
 
// to switch back to the standard clock
game.debug.useStandardClock();
ts
const testClock = game.debug.useTestClock();
 
// Single Step as if we are running 60fps
testClock.step(16.6);
 
// Multiple steps at once, for example 100 steps at 60fps
testClock.run(100, 16.6);
 
// to switch back to the standard clock
game.debug.useStandardClock();