Time
Time
- context : bevy_time::fixed::Fixed
- wrap_period : bevy_utils::Duration
- delta : bevy_utils::Duration
- delta_secs : f32
- delta_secs_f64 : f64
- elapsed : bevy_utils::Duration
- elapsed_secs : f32
- elapsed_secs_f64 : f64
- elapsed_wrapped : bevy_utils::Duration
- elapsed_secs_wrapped : f32
- elapsed_secs_wrapped_f64 : f64
Description
A generic clock resource that tracks how much it has advanced since its previous update and since its creation.
Multiple instances of this resource are inserted automatically by
TimePlugin
:
Time<Real>
tracks real wall-clock time elapsed.Time<Virtual>
tracks virtual game time that may be paused or scaled.Time<Fixed>
tracks fixed timesteps based on virtual time.- [
Time
] is a generic clock that corresponds to "current" or "default" time for systems. It containsTime<Virtual>
except inside theFixedMain
schedule when it containsTime<Fixed>
.The time elapsed since the previous time this clock was advanced is saved as
delta()
and the total amount of time the clock has advanced is saved aselapsed()
. Both are represented as exact [Duration
] values with fixed nanosecond precision. The clock does not support time moving backwards, but it can be updated with [Duration::ZERO
] which will setdelta()
to zero.These values are also available in seconds as
f32
viadelta_secs()
andelapsed_secs()
, and also in seconds asf64
viadelta_secs_f64()
andelapsed_secs_f64()
.Since
elapsed_secs()
will grow constantly and isf32
, it will exhibit gradual precision loss. For applications that require anf32
value but suffer from gradual precision loss there iselapsed_secs_wrapped()
available. The same wrapped value is also available as [Duration
] andf64
for consistency. The wrap period is by default 1 hour, and can be set byset_wrap_period()
.Accessing clocks
By default, any systems requiring current
delta()
orelapsed()
should useRes<Time>
to access the default time configured for the program. By default, this refers toTime<Virtual>
except during theFixedMain
schedule when it refers toTime<Fixed>
. This ensures your system can be used either inUpdate
orFixedUpdate
schedule depending on what is needed.# use bevy_ecs::prelude::*; # use bevy_time::prelude::*; # fn ambivalent_system(time: Res<Time>) { println!("this how I see time: delta {:?}, elapsed {:?}", time.delta(), time.elapsed()); }
If your system needs to react based on real time (wall clock time), like for user interfaces, it should use
Res<Time<Real>>
. Thedelta()
andelapsed()
values will always correspond to real time and will not be affected by pause, time scaling or other tweaks.# use bevy_ecs::prelude::*; # use bevy_time::prelude::*; # fn real_time_system(time: Res<Time<Real>>) { println!("this will always be real time: delta {:?}, elapsed {:?}", time.delta(), time.elapsed()); }
If your system specifically needs to access fixed timestep clock, even when placed in
Update
schedule, you should useRes<Time<Fixed>>
. Thedelta()
andelapsed()
values will correspond to the latest fixed timestep that has been run.# use bevy_ecs::prelude::*; # use bevy_time::prelude::*; # fn fixed_time_system(time: Res<Time<Fixed>>) { println!("this will always be the last executed fixed timestep: delta {:?}, elapsed {:?}", time.delta(), time.elapsed()); }
Finally, if your system specifically needs to know the current virtual game time, even if placed inside
FixedUpdate
, for example to know if the game iswas_paused()
or to useeffective_speed()
, you can useRes<Time<Virtual>>
. However, if the system is placed inFixedUpdate
, extra care must be used because your system might be run multiple times with the samedelta()
andelapsed()
values as the virtual game time has not changed between the iterations.# use bevy_ecs::prelude::*; # use bevy_time::prelude::*; # fn fixed_time_system(time: Res<Time<Virtual>>) { println!("this will be virtual time for this update: delta {:?}, elapsed {:?}", time.delta(), time.elapsed()); println!("also the relative speed of the game is now {}", time.effective_speed()); }
If you need to change the settings for any of the clocks, for example to
pause()
the game, you should useResMut<Time<Virtual>>
.# use bevy_ecs::prelude::*; # use bevy_time::prelude::*; # #[derive(Event)] struct PauseEvent(bool); fn pause_system(mut time: ResMut<Time<Virtual>>, mut events: EventReader<PauseEvent>) { for ev in events.read() { if ev.0 { time.pause(); } else { time.unpause(); } } }
Adding custom clocks
New custom clocks can be created by creating your own struct as a context and passing it to
new_with()
. These clocks can be inserted as resources as normal and then accessed by systems. You can use theadvance_by()
oradvance_to()
methods to move the clock forwards based on your own logic.If you want to add methods for your time instance and they require access to both your context and the generic time part, it's probably simplest to add a custom trait for them and implement it for
Time<Custom>
.Your context struct will need to implement the [
Default
] trait because [Time
] structures support reflection. It also makes initialization trivial by being able to callapp.init_resource::<Time<Custom>>()
.You can also replace the "generic"
Time
clock resource if the "default" time for your game should not be the default virtual time provided. You can get a "generic" snapshot of your clock by callingas_generic()
and then overwrite the [Time
] resource with it. The default systems added byTimePlugin
will overwrite the [Time
] clock duringFirst
andFixedUpdate
schedules.# use bevy_ecs::prelude::*; # use bevy_time::prelude::*; # use bevy_utils::Instant; # #[derive(Debug)] struct Custom { last_external_time: Instant, } impl Default for Custom { fn default() -> Self { Self { last_external_time: Instant::now(), } } } trait CustomTime { fn update_from_external(&mut self, instant: Instant); } impl CustomTime for Time<Custom> { fn update_from_external(&mut self, instant: Instant) { let delta = instant - self.context().last_external_time; self.advance_by(delta); self.context_mut().last_external_time = instant; } }