Skip to content

Time

Compiles

Times in the engine are mostly whole numbers of milliseconds (int), with conversions to seconds (float) when you need them.

Native Gives Use it for
$time.get_gameplay_time_ms() The game’s clock, in ms. Gameplay timing: cooldowns, durations, anything the match cares about.
$time.get_time_ms() Time since this game was started, in ms. Timing that’s purely about this machine.
$time.get_gameplay_tick_interval() Seconds the current frame covers. Moving things smoothly (below).

Convert with $time.ms_to_seconds(ms) and $time.seconds_to_ms(seconds).

The cooldown pattern: remember when it last happened, and compare.

let cooldown_seconds: float = 2.0
let mut last_ms: int = -1000000
fn try_use() -> bool {
let now: int = $time.get_gameplay_time_ms()
if now - last_ms < $time.seconds_to_ms(cooldown_seconds) {
return false
}
last_ms = now
return true
}

Start last_ms far in the past so the first use is never blocked. Keep the setting in seconds, since people think in seconds, and convert where you compare.

There’s no “wait three seconds, then…” statement. Instead, remember when it should happen and check in tick:

let mut explode_at_ms: int = 0
fn arm(delay_seconds: float) {
explode_at_ms = $time.get_gameplay_time_ms() + $time.seconds_to_ms(delay_seconds)
$component.set_event_enabled("tick", true, $component.get())
}
event export fn tick() {
if explode_at_ms == 0 || $time.get_gameplay_time_ms() < explode_at_ms {
return
}
explode_at_ms = 0
$component.set_event_enabled("tick", false, $component.get())
$debug.print_line("boom", null, false)
}

Switching tick on only while something is pending means the component costs nothing the rest of the time.

Frames aren’t all the same length. Scale per-frame movement by the frame’s duration, so speed is in units per second whatever the frame rate:

let speed: float = 200.0 // world units per second
fn step(position: vec3, direction: vec3) -> vec3 {
return position + direction * (speed * $time.get_gameplay_tick_interval())
}

Or compute the position straight from the clock, as the shipped rotator does. It never drifts:

fn height_now() -> float {
let seconds: float = $time.ms_to_seconds($time.get_gameplay_time_ms())
return $math.sin(seconds * 3.1415927) * 50.0
}
For programmers

Gameplay time comes from the global_time singleton; get_time_ms is time since app start and get_system_time_ms the system clock at frame start. There are no timers, coroutines or await; it’s state plus tick, with set_event_enabled to avoid idle ticking.