Skip to main content

Sim

Struct Sim 

Source
pub struct Sim {
    pub world: World,
    pub step: Duration,
    pub max_steps: u32,
    /* private fields */
}
Expand description

Fixed-timestep simulation state.

The game owns a Sim, registers plain systems on its schedule, feeds it wall-clock time every frame with Sim::step, and pulls a snapshot out for the viewport. There is no window, no renderer, and no app object.

Fields§

§world: World

Entity/component store. Game crates add their own components here.

§step: Duration

Fixed step size. Defaults to 60 Hz (see Sim::with_default_step).

Each Sim::tick advances SimTime by exactly this amount, so gameplay stays deterministic regardless of frame rate. Change it before the first Sim::step call; changing it mid-run rescales future ticks but leaves already-simulated time untouched.

§max_steps: u32

Maximum fixed steps per Sim::step call. Defaults to 8.

Guards against the spiral of death: after a long hitch (app resume, debugger pause, slow device), the sim runs at most this many catch-up ticks and drops the excess wall time instead of scheduling dozens of ticks that make the next frame even longer. The dropped time is gone, not carried over. The sim slows down instead of freezing.

Note: clamped to a minimum of 1 per call, so the sim always makes progress while wall time keeps arriving.

Implementations§

Source§

impl Sim

Source

pub fn new(step: Duration) -> Sim

Source

pub fn with_default_step() -> Sim

60 Hz fixed-step sim.

Source

pub fn add_system<M>(&mut self, system: impl IntoSystem<(), (), M>) -> &mut Sim

Register a system into the per-step schedule.

Source

pub fn add_chained_systems<M>( &mut self, systems: impl IntoScheduleConfigs<Box<dyn System<In = (), Out = ()>>, M>, ) -> &mut Sim

Register systems with a guaranteed execution order.

A bare Schedule does not preserve add_system insertion order for systems with conflicting accesses, so multi-step pipelines (economy, combat) must register as one (a, b, c).chain() tuple through here instead of separate add_system calls.

Source

pub fn step(&mut self, dt: Duration) -> u32

Advance the sim by dt wall time, running zero or more fixed steps. Returns the number of steps run.

Wall time accumulates across calls: a dt smaller than Sim::step banks its fraction for later, and a large dt runs several ticks at once. At most Sim::max_steps ticks run per call; any time still banked beyond that is dropped (see Sim::max_steps).

Typical frame pump:

ⓘ
let steps = sim.step(frame_dt);
// `steps` ticks ran; build the viewport snapshot from `sim.world`.
Source

pub fn leftover(&self) -> Duration

Unconsumed fractional time carried to the next frame.

Always less than one Sim::step (a full step would have ticked). Returns Duration::ZERO right after a step boundary and after a hitch that hit the Sim::max_steps cap (the excess is dropped, not reported here).

Source

pub fn alpha(&self) -> f32

Blend factor between the last ticked state and the next one, from 0.0 (just ticked) to 1.0 (a full step banked, tick imminent).

Computed as accumulator / step, clamped to 0..1; returns 0.0 for a degenerate (zero) step size. The sim itself never interpolates. Snapshots read the last ticked state, but games that keep the previous snapshot can blend toward the current one with this factor for smooth rendering.

Note: after a capped hitch (see Sim::max_steps) the accumulator is cleared, so alpha reads 0.0 on the next frame.

Source

pub fn tick(&mut self)

Run the schedule exactly once, advancing sim time by one step. Tick-model games (integer logic steps) drive this directly instead of the wall-clock Sim::step accumulator.

Auto Trait Implementations§

§

impl !Freeze for Sim

§

impl !RefUnwindSafe for Sim

§

impl !UnwindSafe for Sim

§

impl Send for Sim

§

impl Sync for Sim

§

impl Unpin for Sim

§

impl UnsafeUnpin for Sim

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> ConditionalSend for T
where T: Send,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoResult<T> for T

Source§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
Source§

impl<A> Is for A
where A: Any,

Source§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more