bevy_time/
real.rs

1#[cfg(feature = "bevy_reflect")]
2use bevy_reflect::Reflect;
3use bevy_utils::{Duration, Instant};
4
5use crate::time::Time;
6
7/// Real time clock representing elapsed wall clock time.
8///
9/// A specialization of the [`Time`] structure. **For method documentation, see
10/// [`Time<Real>#impl-Time<Real>`].**
11///
12/// It is automatically inserted as a resource by
13/// [`TimePlugin`](crate::TimePlugin) and updated with time instants according
14/// to [`TimeUpdateStrategy`](crate::TimeUpdateStrategy).
15///
16/// The [`delta()`](Time::delta) and [`elapsed()`](Time::elapsed) values of this
17/// clock should be used for anything which deals specifically with real time
18/// (wall clock time). It will not be affected by relative game speed
19/// adjustments, pausing or other adjustments.
20///
21/// The clock does not count time from [`startup()`](Time::startup) to
22/// [`first_update()`](Time::first_update()) into elapsed, but instead will
23/// start counting time from the first update call. [`delta()`](Time::delta) and
24/// [`elapsed()`](Time::elapsed) will report zero on the first update as there
25/// is no previous update instant. This means that a [`delta()`](Time::delta) of
26/// zero must be handled without errors in application logic, as it may
27/// theoretically also happen at other times.
28///
29/// [`Instant`]s for [`startup()`](Time::startup),
30/// [`first_update()`](Time::first_update) and
31/// [`last_update()`](Time::last_update) are recorded and accessible.
32#[derive(Debug, Copy, Clone)]
33#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
34pub struct Real {
35    startup: Instant,
36    first_update: Option<Instant>,
37    last_update: Option<Instant>,
38}
39
40impl Default for Real {
41    fn default() -> Self {
42        Self {
43            startup: Instant::now(),
44            first_update: None,
45            last_update: None,
46        }
47    }
48}
49
50impl Time<Real> {
51    /// Constructs a new `Time<Real>` instance with a specific startup
52    /// [`Instant`].
53    pub fn new(startup: Instant) -> Self {
54        Self::new_with(Real {
55            startup,
56            ..Default::default()
57        })
58    }
59
60    /// Updates the internal time measurements.
61    ///
62    /// Calling this method as part of your app will most likely result in
63    /// inaccurate timekeeping, as the [`Time`] resource is ordinarily managed
64    /// by the [`TimePlugin`](crate::TimePlugin).
65    pub fn update(&mut self) {
66        let instant = Instant::now();
67        self.update_with_instant(instant);
68    }
69
70    /// Updates time with a specified [`Duration`].
71    ///
72    /// This method is provided for use in tests.
73    ///
74    /// Calling this method as part of your app will most likely result in
75    /// inaccurate timekeeping, as the [`Time`] resource is ordinarily managed
76    /// by the [`TimePlugin`](crate::TimePlugin).
77    pub fn update_with_duration(&mut self, duration: Duration) {
78        let last_update = self.context().last_update.unwrap_or(self.context().startup);
79        self.update_with_instant(last_update + duration);
80    }
81
82    /// Updates time with a specified [`Instant`].
83    ///
84    /// This method is provided for use in tests.
85    ///
86    /// Calling this method as part of your app will most likely result in inaccurate timekeeping,
87    /// as the [`Time`] resource is ordinarily managed by the [`TimePlugin`](crate::TimePlugin).
88    pub fn update_with_instant(&mut self, instant: Instant) {
89        let Some(last_update) = self.context().last_update else {
90            let context = self.context_mut();
91            context.first_update = Some(instant);
92            context.last_update = Some(instant);
93            return;
94        };
95        let delta = instant - last_update;
96        self.advance_by(delta);
97        self.context_mut().last_update = Some(instant);
98    }
99
100    /// Returns the [`Instant`] the clock was created.
101    ///
102    /// This usually represents when the app was started.
103    #[inline]
104    pub fn startup(&self) -> Instant {
105        self.context().startup
106    }
107
108    /// Returns the [`Instant`] when [`Self::update`] was first called, if it
109    /// exists.
110    ///
111    /// This usually represents when the first app update started.
112    #[inline]
113    pub fn first_update(&self) -> Option<Instant> {
114        self.context().first_update
115    }
116
117    /// Returns the [`Instant`] when [`Self::update`] was last called, if it
118    /// exists.
119    ///
120    /// This usually represents when the current app update started.
121    #[inline]
122    pub fn last_update(&self) -> Option<Instant> {
123        self.context().last_update
124    }
125}
126
127#[cfg(test)]
128mod test {
129    use super::*;
130
131    #[test]
132    fn test_update() {
133        let startup = Instant::now();
134        let mut time = Time::<Real>::new(startup);
135
136        assert_eq!(time.startup(), startup);
137        assert_eq!(time.first_update(), None);
138        assert_eq!(time.last_update(), None);
139        assert_eq!(time.delta(), Duration::ZERO);
140        assert_eq!(time.elapsed(), Duration::ZERO);
141
142        time.update();
143
144        assert_ne!(time.first_update(), None);
145        assert_ne!(time.last_update(), None);
146        assert_eq!(time.delta(), Duration::ZERO);
147        assert_eq!(time.elapsed(), Duration::ZERO);
148
149        time.update();
150
151        assert_ne!(time.first_update(), None);
152        assert_ne!(time.last_update(), None);
153        assert_ne!(time.last_update(), time.first_update());
154        assert_ne!(time.delta(), Duration::ZERO);
155        assert_eq!(time.elapsed(), time.delta());
156
157        let prev_elapsed = time.elapsed();
158        time.update();
159
160        assert_ne!(time.delta(), Duration::ZERO);
161        assert_eq!(time.elapsed(), prev_elapsed + time.delta());
162    }
163
164    #[test]
165    fn test_update_with_instant() {
166        let startup = Instant::now();
167        let mut time = Time::<Real>::new(startup);
168
169        let first_update = Instant::now();
170        time.update_with_instant(first_update);
171
172        assert_eq!(time.startup(), startup);
173        assert_eq!(time.first_update(), Some(first_update));
174        assert_eq!(time.last_update(), Some(first_update));
175        assert_eq!(time.delta(), Duration::ZERO);
176        assert_eq!(time.elapsed(), Duration::ZERO);
177
178        let second_update = Instant::now();
179        time.update_with_instant(second_update);
180
181        assert_eq!(time.first_update(), Some(first_update));
182        assert_eq!(time.last_update(), Some(second_update));
183        assert_eq!(time.delta(), second_update - first_update);
184        assert_eq!(time.elapsed(), second_update - first_update);
185
186        let third_update = Instant::now();
187        time.update_with_instant(third_update);
188
189        assert_eq!(time.first_update(), Some(first_update));
190        assert_eq!(time.last_update(), Some(third_update));
191        assert_eq!(time.delta(), third_update - second_update);
192        assert_eq!(time.elapsed(), third_update - first_update);
193    }
194
195    #[test]
196    fn test_update_with_duration() {
197        let startup = Instant::now();
198        let mut time = Time::<Real>::new(startup);
199
200        time.update_with_duration(Duration::from_secs(1));
201
202        assert_eq!(time.startup(), startup);
203        assert_eq!(time.first_update(), Some(startup + Duration::from_secs(1)));
204        assert_eq!(time.last_update(), Some(startup + Duration::from_secs(1)));
205        assert_eq!(time.delta(), Duration::ZERO);
206        assert_eq!(time.elapsed(), Duration::ZERO);
207
208        time.update_with_duration(Duration::from_secs(1));
209
210        assert_eq!(time.first_update(), Some(startup + Duration::from_secs(1)));
211        assert_eq!(time.last_update(), Some(startup + Duration::from_secs(2)));
212        assert_eq!(time.delta(), Duration::from_secs(1));
213        assert_eq!(time.elapsed(), Duration::from_secs(1));
214
215        time.update_with_duration(Duration::from_secs(1));
216
217        assert_eq!(time.first_update(), Some(startup + Duration::from_secs(1)));
218        assert_eq!(time.last_update(), Some(startup + Duration::from_secs(3)));
219        assert_eq!(time.delta(), Duration::from_secs(1));
220        assert_eq!(time.elapsed(), Duration::from_secs(2));
221    }
222}