bevy_time/
time.rs

1#[cfg(feature = "bevy_reflect")]
2use bevy_ecs::reflect::ReflectResource;
3use bevy_ecs::system::Resource;
4#[cfg(feature = "bevy_reflect")]
5use bevy_reflect::{std_traits::ReflectDefault, Reflect};
6use bevy_utils::Duration;
7
8/// A generic clock resource that tracks how much it has advanced since its
9/// previous update and since its creation.
10///
11/// Multiple instances of this resource are inserted automatically by
12/// [`TimePlugin`](crate::TimePlugin):
13///
14/// - [`Time<Real>`](crate::real::Real) tracks real wall-clock time elapsed.
15/// - [`Time<Virtual>`](crate::virt::Virtual) tracks virtual game time that may
16///   be paused or scaled.
17/// - [`Time<Fixed>`](crate::fixed::Fixed) tracks fixed timesteps based on
18///   virtual time.
19/// - [`Time`] is a generic clock that corresponds to "current" or "default"
20///   time for systems. It contains [`Time<Virtual>`](crate::virt::Virtual)
21///   except inside the [`FixedMain`](bevy_app::FixedMain) schedule when it
22///   contains [`Time<Fixed>`](crate::fixed::Fixed).
23///
24/// The time elapsed since the previous time this clock was advanced is saved as
25/// [`delta()`](Time::delta) and the total amount of time the clock has advanced
26/// is saved as [`elapsed()`](Time::elapsed). Both are represented as exact
27/// [`Duration`] values with fixed nanosecond precision. The clock does not
28/// support time moving backwards, but it can be updated with [`Duration::ZERO`]
29/// which will set [`delta()`](Time::delta) to zero.
30///
31/// These values are also available in seconds as `f32` via
32/// [`delta_seconds()`](Time::delta_seconds) and
33/// [`elapsed_seconds()`](Time::elapsed_seconds), and also in seconds as `f64`
34/// via [`delta_seconds_f64()`](Time::delta_seconds_f64) and
35/// [`elapsed_seconds_f64()`](Time::elapsed_seconds_f64).
36///
37/// Since [`elapsed_seconds()`](Time::elapsed_seconds) will grow constantly and
38/// is `f32`, it will exhibit gradual precision loss. For applications that
39/// require an `f32` value but suffer from gradual precision loss there is
40/// [`elapsed_seconds_wrapped()`](Time::elapsed_seconds_wrapped) available. The
41/// same wrapped value is also available as [`Duration`] and `f64` for
42/// consistency. The wrap period is by default 1 hour, and can be set by
43/// [`set_wrap_period()`](Time::set_wrap_period).
44///
45/// # Accessing clocks
46///
47/// By default, any systems requiring current [`delta()`](Time::delta) or
48/// [`elapsed()`](Time::elapsed) should use `Res<Time>` to access the default
49/// time configured for the program. By default, this refers to
50/// [`Time<Virtual>`](crate::virt::Virtual) except during the
51/// [`FixedMain`](bevy_app::FixedMain) schedule when it refers to
52/// [`Time<Fixed>`](crate::fixed::Fixed). This ensures your system can be used
53/// either in [`Update`](bevy_app::Update) or
54/// [`FixedUpdate`](bevy_app::FixedUpdate) schedule depending on what is needed.
55///
56/// ```
57/// # use bevy_ecs::prelude::*;
58/// # use bevy_time::prelude::*;
59/// #
60/// fn ambivalent_system(time: Res<Time>) {
61///     println!("this how I see time: delta {:?}, elapsed {:?}", time.delta(), time.elapsed());
62/// }
63/// ```
64///
65/// If your system needs to react based on real time (wall clock time), like for
66/// user interfaces, it should use `Res<Time<Real>>`. The
67/// [`delta()`](Time::delta) and [`elapsed()`](Time::elapsed) values will always
68/// correspond to real time and will not be affected by pause, time scaling or
69/// other tweaks.
70///
71/// ```
72/// # use bevy_ecs::prelude::*;
73/// # use bevy_time::prelude::*;
74/// #
75/// fn real_time_system(time: Res<Time<Real>>) {
76///     println!("this will always be real time: delta {:?}, elapsed {:?}", time.delta(), time.elapsed());
77/// }
78/// ```
79///
80/// If your system specifically needs to access fixed timestep clock, even when
81/// placed in `Update` schedule, you should use `Res<Time<Fixed>>`. The
82/// [`delta()`](Time::delta) and [`elapsed()`](Time::elapsed) values will
83/// correspond to the latest fixed timestep that has been run.
84///
85/// ```
86/// # use bevy_ecs::prelude::*;
87/// # use bevy_time::prelude::*;
88/// #
89/// fn fixed_time_system(time: Res<Time<Fixed>>) {
90///     println!("this will always be the last executed fixed timestep: delta {:?}, elapsed {:?}", time.delta(), time.elapsed());
91/// }
92/// ```
93///
94/// Finally, if your system specifically needs to know the current virtual game
95/// time, even if placed inside [`FixedUpdate`](bevy_app::FixedUpdate), for
96/// example to know if the game is [`was_paused()`](Time::was_paused) or to use
97/// [`effective_speed()`](Time::effective_speed), you can use
98/// `Res<Time<Virtual>>`. However, if the system is placed in
99/// [`FixedUpdate`](bevy_app::FixedUpdate), extra care must be used because your
100/// system might be run multiple times with the same [`delta()`](Time::delta)
101/// and [`elapsed()`](Time::elapsed) values as the virtual game time has not
102/// changed between the iterations.
103///
104/// ```
105/// # use bevy_ecs::prelude::*;
106/// # use bevy_time::prelude::*;
107/// #
108/// fn fixed_time_system(time: Res<Time<Virtual>>) {
109///     println!("this will be virtual time for this update: delta {:?}, elapsed {:?}", time.delta(), time.elapsed());
110///     println!("also the relative speed of the game is now {}", time.effective_speed());
111/// }
112/// ```
113///
114/// If you need to change the settings for any of the clocks, for example to
115/// [`pause()`](Time::pause) the game, you should use `ResMut<Time<Virtual>>`.
116///
117/// ```
118/// # use bevy_ecs::prelude::*;
119/// # use bevy_time::prelude::*;
120/// #
121/// #[derive(Event)]
122/// struct PauseEvent(bool);
123///
124/// fn pause_system(mut time: ResMut<Time<Virtual>>, mut events: EventReader<PauseEvent>) {
125///     for ev in events.read() {
126///         if ev.0 {
127///             time.pause();
128///         } else {
129///             time.unpause();
130///         }
131///     }
132/// }
133/// ```
134///
135/// # Adding custom clocks
136///
137/// New custom clocks can be created by creating your own struct as a context
138/// and passing it to [`new_with()`](Time::new_with). These clocks can be
139/// inserted as resources as normal and then accessed by systems. You can use
140/// the [`advance_by()`](Time::advance_by) or [`advance_to()`](Time::advance_to)
141/// methods to move the clock forwards based on your own logic.
142///
143/// If you want to add methods for your time instance and they require access to
144/// both your context and the generic time part, it's probably simplest to add a
145/// custom trait for them and implement it for `Time<Custom>`.
146///
147/// Your context struct will need to implement the [`Default`] trait because
148/// [`Time`] structures support reflection. It also makes initialization trivial
149/// by being able to call `app.init_resource::<Time<Custom>>()`.
150///
151/// You can also replace the "generic" `Time` clock resource if the "default"
152/// time for your game should not be the default virtual time provided. You can
153/// get a "generic" snapshot of your clock by calling `as_generic()` and then
154/// overwrite the [`Time`] resource with it. The default systems added by
155/// [`TimePlugin`](crate::TimePlugin) will overwrite the [`Time`] clock during
156/// [`First`](bevy_app::First) and [`FixedUpdate`](bevy_app::FixedUpdate)
157/// schedules.
158///
159/// ```
160/// # use bevy_ecs::prelude::*;
161/// # use bevy_time::prelude::*;
162/// # use bevy_utils::Instant;
163/// #
164/// #[derive(Debug)]
165/// struct Custom {
166///     last_external_time: Instant,
167/// }
168///
169/// impl Default for Custom {
170///     fn default() -> Self {
171///         Self {
172///             last_external_time: Instant::now(),
173///         }
174///     }
175/// }
176///
177/// trait CustomTime {
178///     fn update_from_external(&mut self, instant: Instant);
179/// }
180///
181/// impl CustomTime for Time<Custom> {
182///     fn update_from_external(&mut self, instant: Instant) {
183///          let delta = instant - self.context().last_external_time;
184///          self.advance_by(delta);
185///          self.context_mut().last_external_time = instant;
186///     }
187/// }
188/// ```
189#[derive(Resource, Debug, Copy, Clone)]
190#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Resource, Default))]
191pub struct Time<T: Default = ()> {
192    context: T,
193    wrap_period: Duration,
194    delta: Duration,
195    delta_seconds: f32,
196    delta_seconds_f64: f64,
197    elapsed: Duration,
198    elapsed_seconds: f32,
199    elapsed_seconds_f64: f64,
200    elapsed_wrapped: Duration,
201    elapsed_seconds_wrapped: f32,
202    elapsed_seconds_wrapped_f64: f64,
203}
204
205impl<T: Default> Time<T> {
206    const DEFAULT_WRAP_PERIOD: Duration = Duration::from_secs(3600); // 1 hour
207
208    /// Create a new clock from context with [`Self::delta`] and [`Self::elapsed`] starting from
209    /// zero.
210    pub fn new_with(context: T) -> Self {
211        Self {
212            context,
213            ..Default::default()
214        }
215    }
216
217    /// Advance this clock by adding a `delta` duration to it.
218    ///
219    /// The added duration will be returned by [`Self::delta`] and
220    /// [`Self::elapsed`] will be increased by the duration. Adding
221    /// [`Duration::ZERO`] is allowed and will set [`Self::delta`] to zero.
222    pub fn advance_by(&mut self, delta: Duration) {
223        self.delta = delta;
224        self.delta_seconds = self.delta.as_secs_f32();
225        self.delta_seconds_f64 = self.delta.as_secs_f64();
226        self.elapsed += delta;
227        self.elapsed_seconds = self.elapsed.as_secs_f32();
228        self.elapsed_seconds_f64 = self.elapsed.as_secs_f64();
229        self.elapsed_wrapped = duration_rem(self.elapsed, self.wrap_period);
230        self.elapsed_seconds_wrapped = self.elapsed_wrapped.as_secs_f32();
231        self.elapsed_seconds_wrapped_f64 = self.elapsed_wrapped.as_secs_f64();
232    }
233
234    /// Advance this clock to a specific `elapsed` time.
235    ///
236    /// [`Self::delta()`] will return the amount of time the clock was advanced
237    /// and [`Self::elapsed()`] will be the `elapsed` value passed in. Cannot be
238    /// used to move time backwards.
239    ///
240    /// # Panics
241    ///
242    /// Panics if `elapsed` is less than `Self::elapsed()`.
243    pub fn advance_to(&mut self, elapsed: Duration) {
244        assert!(
245            elapsed >= self.elapsed,
246            "tried to move time backwards to an earlier elapsed moment"
247        );
248        self.advance_by(elapsed - self.elapsed);
249    }
250
251    /// Returns the modulus used to calculate [`elapsed_wrapped`](#method.elapsed_wrapped).
252    ///
253    /// **Note:** The default modulus is one hour.
254    #[inline]
255    pub fn wrap_period(&self) -> Duration {
256        self.wrap_period
257    }
258
259    /// Sets the modulus used to calculate [`elapsed_wrapped`](#method.elapsed_wrapped).
260    ///
261    /// **Note:** This will not take effect until the next update.
262    ///
263    /// # Panics
264    ///
265    /// Panics if `wrap_period` is a zero-length duration.
266    #[inline]
267    pub fn set_wrap_period(&mut self, wrap_period: Duration) {
268        assert!(!wrap_period.is_zero(), "division by zero");
269        self.wrap_period = wrap_period;
270    }
271
272    /// Returns how much time has advanced since the last [`update`](#method.update), as a
273    /// [`Duration`].
274    #[inline]
275    pub fn delta(&self) -> Duration {
276        self.delta
277    }
278
279    /// Returns how much time has advanced since the last [`update`](#method.update), as [`f32`]
280    /// seconds.
281    #[inline]
282    pub fn delta_seconds(&self) -> f32 {
283        self.delta_seconds
284    }
285
286    /// Returns how much time has advanced since the last [`update`](#method.update), as [`f64`]
287    /// seconds.
288    #[inline]
289    pub fn delta_seconds_f64(&self) -> f64 {
290        self.delta_seconds_f64
291    }
292
293    /// Returns how much time has advanced since [`startup`](#method.startup), as [`Duration`].
294    #[inline]
295    pub fn elapsed(&self) -> Duration {
296        self.elapsed
297    }
298
299    /// Returns how much time has advanced since [`startup`](#method.startup), as [`f32`] seconds.
300    ///
301    /// **Note:** This is a monotonically increasing value. Its precision will degrade over time.
302    /// If you need an `f32` but that precision loss is unacceptable,
303    /// use [`elapsed_seconds_wrapped`](#method.elapsed_seconds_wrapped).
304    #[inline]
305    pub fn elapsed_seconds(&self) -> f32 {
306        self.elapsed_seconds
307    }
308
309    /// Returns how much time has advanced since [`startup`](#method.startup), as [`f64`] seconds.
310    #[inline]
311    pub fn elapsed_seconds_f64(&self) -> f64 {
312        self.elapsed_seconds_f64
313    }
314
315    /// Returns how much time has advanced since [`startup`](#method.startup) modulo
316    /// the [`wrap_period`](#method.wrap_period), as [`Duration`].
317    #[inline]
318    pub fn elapsed_wrapped(&self) -> Duration {
319        self.elapsed_wrapped
320    }
321
322    /// Returns how much time has advanced since [`startup`](#method.startup) modulo
323    /// the [`wrap_period`](#method.wrap_period), as [`f32`] seconds.
324    ///
325    /// This method is intended for applications (e.g. shaders) that require an [`f32`] value but
326    /// suffer from the gradual precision loss of [`elapsed_seconds`](#method.elapsed_seconds).
327    #[inline]
328    pub fn elapsed_seconds_wrapped(&self) -> f32 {
329        self.elapsed_seconds_wrapped
330    }
331
332    /// Returns how much time has advanced since [`startup`](#method.startup) modulo
333    /// the [`wrap_period`](#method.wrap_period), as [`f64`] seconds.
334    #[inline]
335    pub fn elapsed_seconds_wrapped_f64(&self) -> f64 {
336        self.elapsed_seconds_wrapped_f64
337    }
338
339    /// Returns a reference to the context of this specific clock.
340    #[inline]
341    pub fn context(&self) -> &T {
342        &self.context
343    }
344
345    /// Returns a mutable reference to the context of this specific clock.
346    #[inline]
347    pub fn context_mut(&mut self) -> &mut T {
348        &mut self.context
349    }
350
351    /// Returns a copy of this clock as fully generic clock without context.
352    #[inline]
353    pub fn as_generic(&self) -> Time<()> {
354        Time {
355            context: (),
356            wrap_period: self.wrap_period,
357            delta: self.delta,
358            delta_seconds: self.delta_seconds,
359            delta_seconds_f64: self.delta_seconds_f64,
360            elapsed: self.elapsed,
361            elapsed_seconds: self.elapsed_seconds,
362            elapsed_seconds_f64: self.elapsed_seconds_f64,
363            elapsed_wrapped: self.elapsed_wrapped,
364            elapsed_seconds_wrapped: self.elapsed_seconds_wrapped,
365            elapsed_seconds_wrapped_f64: self.elapsed_seconds_wrapped_f64,
366        }
367    }
368}
369
370impl<T: Default> Default for Time<T> {
371    fn default() -> Self {
372        Self {
373            context: Default::default(),
374            wrap_period: Self::DEFAULT_WRAP_PERIOD,
375            delta: Duration::ZERO,
376            delta_seconds: 0.0,
377            delta_seconds_f64: 0.0,
378            elapsed: Duration::ZERO,
379            elapsed_seconds: 0.0,
380            elapsed_seconds_f64: 0.0,
381            elapsed_wrapped: Duration::ZERO,
382            elapsed_seconds_wrapped: 0.0,
383            elapsed_seconds_wrapped_f64: 0.0,
384        }
385    }
386}
387
388fn duration_rem(dividend: Duration, divisor: Duration) -> Duration {
389    // `Duration` does not have a built-in modulo operation
390    let quotient = (dividend.as_nanos() / divisor.as_nanos()) as u32;
391    dividend - (quotient * divisor)
392}
393
394#[cfg(test)]
395mod test {
396    use super::*;
397
398    #[test]
399    fn test_initial_state() {
400        let time: Time = Time::default();
401
402        assert_eq!(time.wrap_period(), Time::<()>::DEFAULT_WRAP_PERIOD);
403        assert_eq!(time.delta(), Duration::ZERO);
404        assert_eq!(time.delta_seconds(), 0.0);
405        assert_eq!(time.delta_seconds_f64(), 0.0);
406        assert_eq!(time.elapsed(), Duration::ZERO);
407        assert_eq!(time.elapsed_seconds(), 0.0);
408        assert_eq!(time.elapsed_seconds_f64(), 0.0);
409        assert_eq!(time.elapsed_wrapped(), Duration::ZERO);
410        assert_eq!(time.elapsed_seconds_wrapped(), 0.0);
411        assert_eq!(time.elapsed_seconds_wrapped_f64(), 0.0);
412    }
413
414    #[test]
415    fn test_advance_by() {
416        let mut time: Time = Time::default();
417
418        time.advance_by(Duration::from_millis(250));
419
420        assert_eq!(time.delta(), Duration::from_millis(250));
421        assert_eq!(time.delta_seconds(), 0.25);
422        assert_eq!(time.delta_seconds_f64(), 0.25);
423        assert_eq!(time.elapsed(), Duration::from_millis(250));
424        assert_eq!(time.elapsed_seconds(), 0.25);
425        assert_eq!(time.elapsed_seconds_f64(), 0.25);
426
427        time.advance_by(Duration::from_millis(500));
428
429        assert_eq!(time.delta(), Duration::from_millis(500));
430        assert_eq!(time.delta_seconds(), 0.5);
431        assert_eq!(time.delta_seconds_f64(), 0.5);
432        assert_eq!(time.elapsed(), Duration::from_millis(750));
433        assert_eq!(time.elapsed_seconds(), 0.75);
434        assert_eq!(time.elapsed_seconds_f64(), 0.75);
435
436        time.advance_by(Duration::ZERO);
437
438        assert_eq!(time.delta(), Duration::ZERO);
439        assert_eq!(time.delta_seconds(), 0.0);
440        assert_eq!(time.delta_seconds_f64(), 0.0);
441        assert_eq!(time.elapsed(), Duration::from_millis(750));
442        assert_eq!(time.elapsed_seconds(), 0.75);
443        assert_eq!(time.elapsed_seconds_f64(), 0.75);
444    }
445
446    #[test]
447    fn test_advance_to() {
448        let mut time: Time = Time::default();
449
450        time.advance_to(Duration::from_millis(250));
451
452        assert_eq!(time.delta(), Duration::from_millis(250));
453        assert_eq!(time.delta_seconds(), 0.25);
454        assert_eq!(time.delta_seconds_f64(), 0.25);
455        assert_eq!(time.elapsed(), Duration::from_millis(250));
456        assert_eq!(time.elapsed_seconds(), 0.25);
457        assert_eq!(time.elapsed_seconds_f64(), 0.25);
458
459        time.advance_to(Duration::from_millis(750));
460
461        assert_eq!(time.delta(), Duration::from_millis(500));
462        assert_eq!(time.delta_seconds(), 0.5);
463        assert_eq!(time.delta_seconds_f64(), 0.5);
464        assert_eq!(time.elapsed(), Duration::from_millis(750));
465        assert_eq!(time.elapsed_seconds(), 0.75);
466        assert_eq!(time.elapsed_seconds_f64(), 0.75);
467
468        time.advance_to(Duration::from_millis(750));
469
470        assert_eq!(time.delta(), Duration::ZERO);
471        assert_eq!(time.delta_seconds(), 0.0);
472        assert_eq!(time.delta_seconds_f64(), 0.0);
473        assert_eq!(time.elapsed(), Duration::from_millis(750));
474        assert_eq!(time.elapsed_seconds(), 0.75);
475        assert_eq!(time.elapsed_seconds_f64(), 0.75);
476    }
477
478    #[test]
479    #[should_panic]
480    fn test_advance_to_backwards_panics() {
481        let mut time: Time = Time::default();
482
483        time.advance_to(Duration::from_millis(750));
484
485        time.advance_to(Duration::from_millis(250));
486    }
487
488    #[test]
489    fn test_wrapping() {
490        let mut time: Time = Time::default();
491        time.set_wrap_period(Duration::from_secs(3));
492
493        time.advance_by(Duration::from_secs(2));
494
495        assert_eq!(time.elapsed_wrapped(), Duration::from_secs(2));
496        assert_eq!(time.elapsed_seconds_wrapped(), 2.0);
497        assert_eq!(time.elapsed_seconds_wrapped_f64(), 2.0);
498
499        time.advance_by(Duration::from_secs(2));
500
501        assert_eq!(time.elapsed_wrapped(), Duration::from_secs(1));
502        assert_eq!(time.elapsed_seconds_wrapped(), 1.0);
503        assert_eq!(time.elapsed_seconds_wrapped_f64(), 1.0);
504
505        time.advance_by(Duration::from_secs(2));
506
507        assert_eq!(time.elapsed_wrapped(), Duration::ZERO);
508        assert_eq!(time.elapsed_seconds_wrapped(), 0.0);
509        assert_eq!(time.elapsed_seconds_wrapped_f64(), 0.0);
510
511        time.advance_by(Duration::new(3, 250_000_000));
512
513        assert_eq!(time.elapsed_wrapped(), Duration::from_millis(250));
514        assert_eq!(time.elapsed_seconds_wrapped(), 0.25);
515        assert_eq!(time.elapsed_seconds_wrapped_f64(), 0.25);
516    }
517
518    #[test]
519    fn test_wrapping_change() {
520        let mut time: Time = Time::default();
521        time.set_wrap_period(Duration::from_secs(5));
522
523        time.advance_by(Duration::from_secs(8));
524
525        assert_eq!(time.elapsed_wrapped(), Duration::from_secs(3));
526        assert_eq!(time.elapsed_seconds_wrapped(), 3.0);
527        assert_eq!(time.elapsed_seconds_wrapped_f64(), 3.0);
528
529        time.set_wrap_period(Duration::from_secs(2));
530
531        assert_eq!(time.elapsed_wrapped(), Duration::from_secs(3));
532        assert_eq!(time.elapsed_seconds_wrapped(), 3.0);
533        assert_eq!(time.elapsed_seconds_wrapped_f64(), 3.0);
534
535        time.advance_by(Duration::ZERO);
536
537        // Time will wrap to modulo duration from full `elapsed()`, not to what
538        // is left in `elapsed_wrapped()`. This test of values is here to ensure
539        // that we notice if we change that behaviour.
540        assert_eq!(time.elapsed_wrapped(), Duration::from_secs(0));
541        assert_eq!(time.elapsed_seconds_wrapped(), 0.0);
542        assert_eq!(time.elapsed_seconds_wrapped_f64(), 0.0);
543    }
544}