pub struct FrameClock { /* private fields */ }Expand description
Fixed-timestep accumulator plus variable render delta.
See the module docs for the loop shape.
Implementations§
Source§impl FrameClock
impl FrameClock
Sourcepub fn new(tick_hz: u32) -> Self
pub fn new(tick_hz: u32) -> Self
A clock running the simulation at tick_hz.
§Panics
If tick_hz is zero, or over one tick per nanosecond — the period below
is truncating integer nanoseconds, so a rate past 1 GHz rounds to a
period of zero and there is no clock to build. It used to reach
with_period and fail there, blaming a period the
caller never passed.
Sourcepub fn with_period(period: Duration) -> Self
pub fn with_period(period: Duration) -> Self
Sourcepub const fn set_max_catch_up_ticks(&mut self, ticks: u32)
pub const fn set_max_catch_up_ticks(&mut self, ticks: u32)
Caps how many ticks a single FrameClock::update may queue.
This is the spiral-of-death guard. If a frame takes longer than the
ticks it queues take to simulate, the accumulator grows, which queues
more ticks, which take longer still — the simulation never catches up
and the game locks solid. Past the cap, surplus wall-clock time is
discarded: those ticks never run, so simulation time falls
permanently behind wall time (a hitch is a hitch — nothing rewinds it),
but the frame rate recovers instead of collapsing. The count of skipped
ticks is available from FrameClock::dropped_ticks and is worth
logging; in a multiplayer build it is the client’s cue that it has
desynced from the server’s tick timeline.
The default, DEFAULT_MAX_CATCH_UP_TICKS, allows 8 ticks — 133 ms of
catch-up at 60 Hz, enough to absorb an asset-load or shader-compile
hitch without letting a slow machine dig itself into a hole.
§Panics
If ticks is zero — a clock that can never tick is never what you want.
Sourcepub fn update(&mut self, now: Duration)
pub fn update(&mut self, now: Duration)
Feeds the clock the current timestamp. Call once per frame, before the tick loop.
Timestamps must come from a TimeSource. A timestamp that moves
backwards (a source that is not actually monotonic) contributes zero
time and bumps FrameClock::backwards_updates rather than panicking
or wrapping.
Sourcepub const fn consume_tick(&mut self) -> bool
pub const fn consume_tick(&mut self) -> bool
Takes one pending tick, if the accumulator holds a whole one.
Drive it as while clock.consume_tick() { server_tick(); }.
Sourcepub const fn pending_ticks(&self) -> u32
pub const fn pending_ticks(&self) -> u32
How many ticks FrameClock::consume_tick would still yield.
Sourcepub const fn next_tick_due(&self) -> Option<Duration>
pub const fn next_tick_due(&self) -> Option<Duration>
When the next tick comes due, on the timeline
FrameClock::update is fed: the last update, plus whatever the
accumulator still lacks of a whole tick. A tick already pending is due
at the last update. None before the first update, which has no
timeline to answer on.
What a loop that has nothing to render may sleep until: no tick is due before this, so a wait that ends here keeps the simulation on schedule.
Sourcepub const fn tick_dt(&self) -> Duration
pub const fn tick_dt(&self) -> Duration
The fixed simulation step. Every tick advances the world by exactly this much, whatever the frame rate.
Sourcepub fn tick_dt_secs(&self) -> f64
pub fn tick_dt_secs(&self) -> f64
FrameClock::tick_dt in seconds, for integrators.
Sourcepub const fn render_dt(&self) -> Duration
pub const fn render_dt(&self) -> Duration
Wall-clock time covered by the last FrameClock::update — the
variable render delta, for camera smoothing, UI animation and anything
else that is not simulation.
Sourcepub fn render_dt_secs(&self) -> f32
pub fn render_dt_secs(&self) -> f32
FrameClock::render_dt in seconds.
Sourcepub fn alpha(&self) -> f32
pub fn alpha(&self) -> f32
How far the render frame sits between the last simulated tick and the
next one, in [0, 1).
Interpolated rendering wants lerp(previous_state, current_state, alpha). Call it after draining the tick loop; called before, the
accumulator may still hold whole ticks, in which case this saturates
just below 1.0 rather than reporting a fraction greater than one.
Sourcepub const fn dropped_ticks(&self) -> u64
pub const fn dropped_ticks(&self) -> u64
Ticks discarded by the catch-up cap since the clock was created.
Sourcepub const fn backwards_updates(&self) -> u64
pub const fn backwards_updates(&self) -> u64
Number of FrameClock::update calls whose timestamp went backwards.
Non-zero means the time source is broken.