Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Time

Timing values are on world.resources.window.timing. There is no separate Time resource. Putting timing on the window struct matches the way the engine treats it, since timing is updated by the same code that updates the window each frame.

WindowTiming

#![allow(unused)]
fn main() {
pub struct WindowTiming {
    pub frames_per_second: f32,
    pub delta_time: f32,
    pub raw_delta_time: f32,
    pub time_speed: f32,
    pub last_frame_start_instant: Option<web_time::Instant>,
    pub current_frame_start_instant: Option<web_time::Instant>,
    pub initial_frame_start_instant: Option<web_time::Instant>,
    pub frame_counter: u32,
    pub uptime_milliseconds: u64,
}
}

delta_time is the scaled time in seconds since the previous frame. raw_delta_time is the unscaled value, before time_speed is applied. frames_per_second is the running rate. frame_counter is the count of frames since startup. uptime_milliseconds is wall-clock time since startup. The three Instant fields are the underlying timestamps used to compute the others.

Reading Time

#![allow(unused)]
fn main() {
fn run_systems(&mut self, world: &mut World) {
    let dt = world.resources.window.timing.delta_time;
    let fps = world.resources.window.timing.frames_per_second;
    let elapsed = world.resources.window.timing.uptime_milliseconds as f32 / 1000.0;
    let frame = world.resources.window.timing.frame_counter;
}
}

Delta Time

delta_time is the value to multiply by when computing per-frame change. Movement, rotation, animation, anything that should happen at a consistent rate regardless of frame rate.

#![allow(unused)]
fn main() {
fn move_entity(world: &mut World, entity: Entity, velocity: Vec3) {
    let dt = world.resources.window.timing.delta_time;
    if let Some(transform) = world.core.get_local_transform_mut(entity) {
        transform.translation += velocity * dt;
    }
}
}

raw_delta_time ignores time_speed. Use it for things that should not respect time scaling. UI animations should keep going during a slow-motion gameplay moment, so the UI uses raw_delta_time. Gameplay physics that should slow down uses delta_time.

Time Speed

time_speed scales delta_time. The relation is delta_time = raw_delta_time * time_speed, so setting time_speed to zero freezes all delta_time-driven logic without stopping the render loop.

#![allow(unused)]
fn main() {
world.resources.window.timing.time_speed = 0.5;
world.resources.window.timing.time_speed = 2.0;
world.resources.window.timing.time_speed = 0.0;
}

The render loop keeps running at full rate. The frame counter still advances. Animations or UI driven by raw_delta_time still play. Only the values keyed off delta_time freeze.

Periodic Actions

For an action that fires every N seconds, accumulate delta_time into an f32 and reset when the accumulator crosses the threshold.

#![allow(unused)]
fn main() {
struct MyGame {
    spawn_timer: f32,
}

fn run_systems(&mut self, world: &mut World) {
    let dt = world.resources.window.timing.delta_time;
    self.spawn_timer += dt;
    if self.spawn_timer >= 2.0 {
        spawn_enemy(world);
        self.spawn_timer = 0.0;
    }
}
}

For very long intervals, the simpler approach is to check frame_counter or uptime_milliseconds directly.

Uptime

uptime_milliseconds is total wall-clock time since the application started. The standard use is driving shader animations that should loop continuously.

#![allow(unused)]
fn main() {
let time = world.resources.window.timing.uptime_milliseconds as f32 / 1000.0;
let wave = (time * 2.0).sin();
}

uptime_milliseconds is wall-clock and ignores time_speed, so a slow-motion effect does not affect a uniform shader wave.

Web Compatibility

The Instant fields use web_time::Instant, not std::time::Instant. std::time::Instant does not compile to wasm32 because the underlying system call is not available in the browser. web_time::Instant is a drop-in replacement that uses performance.now() on the web and falls back to std::time::Instant on native, so the same code runs on both targets without conditional compilation.