bevy_time/
timer.rs

1use crate::Stopwatch;
2#[cfg(feature = "bevy_reflect")]
3use bevy_reflect::prelude::*;
4use bevy_utils::Duration;
5
6/// Tracks elapsed time. Enters the finished state once `duration` is reached.
7///
8/// Non repeating timers will stop tracking and stay in the finished state until reset.
9/// Repeating timers will only be in the finished state on each tick `duration` is reached or
10/// exceeded, and can still be reset at any given point.
11///
12/// Paused timers will not have elapsed time increased.
13///
14/// Note that in order to advance the timer [`tick`](Timer::tick) **MUST** be called.
15#[derive(Clone, Debug, Default, PartialEq, Eq)]
16#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
17#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default))]
18pub struct Timer {
19    stopwatch: Stopwatch,
20    duration: Duration,
21    mode: TimerMode,
22    finished: bool,
23    times_finished_this_tick: u32,
24}
25
26impl Timer {
27    /// Creates a new timer with a given duration.
28    ///
29    /// See also [`Timer::from_seconds`](Timer::from_seconds).
30    pub fn new(duration: Duration, mode: TimerMode) -> Self {
31        Self {
32            duration,
33            mode,
34            ..Default::default()
35        }
36    }
37
38    /// Creates a new timer with a given duration in seconds.
39    ///
40    /// # Example
41    /// ```
42    /// # use bevy_time::*;
43    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
44    /// ```
45    pub fn from_seconds(duration: f32, mode: TimerMode) -> Self {
46        Self {
47            duration: Duration::from_secs_f32(duration),
48            mode,
49            ..Default::default()
50        }
51    }
52
53    /// Returns `true` if the timer has reached its duration.
54    ///
55    /// For repeating timers, this method behaves identically to [`Timer::just_finished`].
56    ///
57    /// # Examples
58    /// ```
59    /// # use bevy_time::*;
60    /// use std::time::Duration;
61    ///
62    /// let mut timer_once = Timer::from_seconds(1.0, TimerMode::Once);
63    /// timer_once.tick(Duration::from_secs_f32(1.5));
64    /// assert!(timer_once.finished());
65    /// timer_once.tick(Duration::from_secs_f32(0.5));
66    /// assert!(timer_once.finished());
67    ///
68    /// let mut timer_repeating = Timer::from_seconds(1.0, TimerMode::Repeating);
69    /// timer_repeating.tick(Duration::from_secs_f32(1.1));
70    /// assert!(timer_repeating.finished());
71    /// timer_repeating.tick(Duration::from_secs_f32(0.8));
72    /// assert!(!timer_repeating.finished());
73    /// timer_repeating.tick(Duration::from_secs_f32(0.6));
74    /// assert!(timer_repeating.finished());
75    /// ```
76    #[inline]
77    pub fn finished(&self) -> bool {
78        self.finished
79    }
80
81    /// Returns `true` only on the tick the timer reached its duration.
82    ///
83    /// # Examples
84    /// ```
85    /// # use bevy_time::*;
86    /// use std::time::Duration;
87    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
88    /// timer.tick(Duration::from_secs_f32(1.5));
89    /// assert!(timer.just_finished());
90    /// timer.tick(Duration::from_secs_f32(0.5));
91    /// assert!(!timer.just_finished());
92    /// ```
93    #[inline]
94    pub fn just_finished(&self) -> bool {
95        self.times_finished_this_tick > 0
96    }
97
98    /// Returns the time elapsed on the timer. Guaranteed to be between 0.0 and `duration`.
99    /// Will only equal `duration` when the timer is finished and non repeating.
100    ///
101    /// See also [`Stopwatch::elapsed`](Stopwatch::elapsed).
102    ///
103    /// # Examples
104    /// ```
105    /// # use bevy_time::*;
106    /// use std::time::Duration;
107    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
108    /// timer.tick(Duration::from_secs_f32(0.5));
109    /// assert_eq!(timer.elapsed(), Duration::from_secs_f32(0.5));
110    /// ```
111    #[inline]
112    pub fn elapsed(&self) -> Duration {
113        self.stopwatch.elapsed()
114    }
115
116    /// Returns the time elapsed on the timer as an `f32`.
117    /// See also [`Timer::elapsed`](Timer::elapsed).
118    #[inline]
119    pub fn elapsed_secs(&self) -> f32 {
120        self.stopwatch.elapsed_secs()
121    }
122
123    /// Sets the elapsed time of the timer without any other considerations.
124    ///
125    /// See also [`Stopwatch::set`](Stopwatch::set).
126    ///
127    /// #
128    /// ```
129    /// # use bevy_time::*;
130    /// use std::time::Duration;
131    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
132    /// timer.set_elapsed(Duration::from_secs(2));
133    /// assert_eq!(timer.elapsed(), Duration::from_secs(2));
134    /// // the timer is not finished even if the elapsed time is greater than the duration.
135    /// assert!(!timer.finished());
136    /// ```
137    #[inline]
138    pub fn set_elapsed(&mut self, time: Duration) {
139        self.stopwatch.set_elapsed(time);
140    }
141
142    /// Returns the duration of the timer.
143    ///
144    /// # Examples
145    /// ```
146    /// # use bevy_time::*;
147    /// use std::time::Duration;
148    /// let timer = Timer::new(Duration::from_secs(1), TimerMode::Once);
149    /// assert_eq!(timer.duration(), Duration::from_secs(1));
150    /// ```
151    #[inline]
152    pub fn duration(&self) -> Duration {
153        self.duration
154    }
155
156    /// Sets the duration of the timer.
157    ///
158    /// # Examples
159    /// ```
160    /// # use bevy_time::*;
161    /// use std::time::Duration;
162    /// let mut timer = Timer::from_seconds(1.5, TimerMode::Once);
163    /// timer.set_duration(Duration::from_secs(1));
164    /// assert_eq!(timer.duration(), Duration::from_secs(1));
165    /// ```
166    #[inline]
167    pub fn set_duration(&mut self, duration: Duration) {
168        self.duration = duration;
169    }
170
171    /// Returns the mode of the timer.
172    ///
173    /// # Examples
174    /// ```
175    /// # use bevy_time::*;
176    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);
177    /// assert_eq!(timer.mode(), TimerMode::Repeating);
178    /// ```
179    #[inline]
180    pub fn mode(&self) -> TimerMode {
181        self.mode
182    }
183
184    /// Sets the mode of the timer.
185    ///
186    /// # Examples
187    /// ```
188    /// # use bevy_time::*;
189    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);
190    /// timer.set_mode(TimerMode::Once);
191    /// assert_eq!(timer.mode(), TimerMode::Once);
192    /// ```
193    #[doc(alias = "repeating")]
194    #[inline]
195    pub fn set_mode(&mut self, mode: TimerMode) {
196        if self.mode != TimerMode::Repeating && mode == TimerMode::Repeating && self.finished {
197            self.stopwatch.reset();
198            self.finished = self.just_finished();
199        }
200        self.mode = mode;
201    }
202
203    /// Advance the timer by `delta` seconds.
204    /// Non repeating timer will clamp at duration.
205    /// Repeating timer will wrap around.
206    /// Will not affect paused timers.
207    ///
208    /// See also [`Stopwatch::tick`](Stopwatch::tick).
209    ///
210    /// # Examples
211    /// ```
212    /// # use bevy_time::*;
213    /// use std::time::Duration;
214    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
215    /// let mut repeating = Timer::from_seconds(1.0, TimerMode::Repeating);
216    /// timer.tick(Duration::from_secs_f32(1.5));
217    /// repeating.tick(Duration::from_secs_f32(1.5));
218    /// assert_eq!(timer.elapsed_secs(), 1.0);
219    /// assert_eq!(repeating.elapsed_secs(), 0.5);
220    /// ```
221    pub fn tick(&mut self, delta: Duration) -> &Self {
222        if self.paused() {
223            self.times_finished_this_tick = 0;
224            if self.mode == TimerMode::Repeating {
225                self.finished = false;
226            }
227            return self;
228        }
229
230        if self.mode != TimerMode::Repeating && self.finished() {
231            self.times_finished_this_tick = 0;
232            return self;
233        }
234
235        self.stopwatch.tick(delta);
236        self.finished = self.elapsed() >= self.duration();
237
238        if self.finished() {
239            if self.mode == TimerMode::Repeating {
240                self.times_finished_this_tick = self
241                    .elapsed()
242                    .as_nanos()
243                    .checked_div(self.duration().as_nanos())
244                    .map_or(u32::MAX, |x| x as u32);
245                self.set_elapsed(
246                    self.elapsed()
247                        .as_nanos()
248                        .checked_rem(self.duration().as_nanos())
249                        .map_or(Duration::ZERO, |x| Duration::from_nanos(x as u64)),
250                );
251            } else {
252                self.times_finished_this_tick = 1;
253                self.set_elapsed(self.duration());
254            }
255        } else {
256            self.times_finished_this_tick = 0;
257        }
258
259        self
260    }
261
262    /// Pauses the Timer. Disables the ticking of the timer.
263    ///
264    /// See also [`Stopwatch::pause`](Stopwatch::pause).
265    ///
266    /// # Examples
267    /// ```
268    /// # use bevy_time::*;
269    /// use std::time::Duration;
270    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
271    /// timer.pause();
272    /// timer.tick(Duration::from_secs_f32(0.5));
273    /// assert_eq!(timer.elapsed_secs(), 0.0);
274    /// ```
275    #[inline]
276    pub fn pause(&mut self) {
277        self.stopwatch.pause();
278    }
279
280    /// Unpauses the Timer. Resumes the ticking of the timer.
281    ///
282    /// See also [`Stopwatch::unpause()`](Stopwatch::unpause).
283    ///
284    /// # Examples
285    /// ```
286    /// # use bevy_time::*;
287    /// use std::time::Duration;
288    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
289    /// timer.pause();
290    /// timer.tick(Duration::from_secs_f32(0.5));
291    /// timer.unpause();
292    /// timer.tick(Duration::from_secs_f32(0.5));
293    /// assert_eq!(timer.elapsed_secs(), 0.5);
294    /// ```
295    #[inline]
296    pub fn unpause(&mut self) {
297        self.stopwatch.unpause();
298    }
299
300    /// Returns `true` if the timer is paused.
301    ///
302    /// See also [`Stopwatch::paused`](Stopwatch::paused).
303    ///
304    /// # Examples
305    /// ```
306    /// # use bevy_time::*;
307    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
308    /// assert!(!timer.paused());
309    /// timer.pause();
310    /// assert!(timer.paused());
311    /// timer.unpause();
312    /// assert!(!timer.paused());
313    /// ```
314    #[inline]
315    pub fn paused(&self) -> bool {
316        self.stopwatch.paused()
317    }
318
319    /// Resets the timer. The reset doesn't affect the `paused` state of the timer.
320    ///
321    /// See also [`Stopwatch::reset`](Stopwatch::reset).
322    ///
323    /// Examples
324    /// ```
325    /// # use bevy_time::*;
326    /// use std::time::Duration;
327    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
328    /// timer.tick(Duration::from_secs_f32(1.5));
329    /// timer.reset();
330    /// assert!(!timer.finished());
331    /// assert!(!timer.just_finished());
332    /// assert_eq!(timer.elapsed_secs(), 0.0);
333    /// ```
334    pub fn reset(&mut self) {
335        self.stopwatch.reset();
336        self.finished = false;
337        self.times_finished_this_tick = 0;
338    }
339
340    /// Returns the fraction of the timer elapsed time (goes from 0.0 to 1.0).
341    ///
342    /// # Examples
343    /// ```
344    /// # use bevy_time::*;
345    /// use std::time::Duration;
346    /// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);
347    /// timer.tick(Duration::from_secs_f32(0.5));
348    /// assert_eq!(timer.fraction(), 0.25);
349    /// ```
350    #[inline]
351    pub fn fraction(&self) -> f32 {
352        if self.duration == Duration::ZERO {
353            1.0
354        } else {
355            self.elapsed().as_secs_f32() / self.duration().as_secs_f32()
356        }
357    }
358
359    /// Returns the fraction of the timer remaining time (goes from 1.0 to 0.0).
360    ///
361    /// # Examples
362    /// ```
363    /// # use bevy_time::*;
364    /// use std::time::Duration;
365    /// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);
366    /// timer.tick(Duration::from_secs_f32(0.5));
367    /// assert_eq!(timer.fraction_remaining(), 0.75);
368    /// ```
369    #[inline]
370    pub fn fraction_remaining(&self) -> f32 {
371        1.0 - self.fraction()
372    }
373
374    /// Returns the remaining time in seconds
375    ///
376    /// # Examples
377    /// ```
378    /// # use bevy_time::*;
379    /// use std::cmp::Ordering;
380    /// use std::time::Duration;
381    /// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);
382    /// timer.tick(Duration::from_secs_f32(0.5));
383    /// let result = timer.remaining_secs().total_cmp(&1.5);
384    /// assert_eq!(Ordering::Equal, result);
385    /// ```
386    #[inline]
387    pub fn remaining_secs(&self) -> f32 {
388        self.remaining().as_secs_f32()
389    }
390
391    /// Returns the remaining time using Duration
392    ///
393    /// # Examples
394    /// ```
395    /// # use bevy_time::*;
396    /// use std::time::Duration;
397    /// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);
398    /// timer.tick(Duration::from_secs_f32(0.5));
399    /// assert_eq!(timer.remaining(), Duration::from_secs_f32(1.5));
400    /// ```
401    #[inline]
402    pub fn remaining(&self) -> Duration {
403        self.duration() - self.elapsed()
404    }
405
406    /// Returns the number of times a repeating timer
407    /// finished during the last [`tick`](Timer<T>::tick) call.
408    ///
409    /// For non repeating-timers, this method will only ever
410    /// return 0 or 1.
411    ///
412    /// # Examples
413    /// ```
414    /// # use bevy_time::*;
415    /// use std::time::Duration;
416    /// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);
417    /// timer.tick(Duration::from_secs_f32(6.0));
418    /// assert_eq!(timer.times_finished_this_tick(), 6);
419    /// timer.tick(Duration::from_secs_f32(2.0));
420    /// assert_eq!(timer.times_finished_this_tick(), 2);
421    /// timer.tick(Duration::from_secs_f32(0.5));
422    /// assert_eq!(timer.times_finished_this_tick(), 0);
423    /// ```
424    #[inline]
425    pub fn times_finished_this_tick(&self) -> u32 {
426        self.times_finished_this_tick
427    }
428}
429
430/// Specifies [`Timer`] behavior.
431#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
432#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
433#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default))]
434pub enum TimerMode {
435    /// Run once and stop.
436    #[default]
437    Once,
438    /// Reset when finished.
439    Repeating,
440}
441
442#[cfg(test)]
443#[allow(clippy::float_cmp)]
444mod tests {
445    use super::*;
446
447    #[test]
448    fn non_repeating_timer() {
449        let mut t = Timer::from_seconds(10.0, TimerMode::Once);
450        // Tick once, check all attributes
451        t.tick(Duration::from_secs_f32(0.25));
452        assert_eq!(t.elapsed_secs(), 0.25);
453        assert_eq!(t.duration(), Duration::from_secs_f32(10.0));
454        assert!(!t.finished());
455        assert!(!t.just_finished());
456        assert_eq!(t.times_finished_this_tick(), 0);
457        assert_eq!(t.mode(), TimerMode::Once);
458        assert_eq!(t.fraction(), 0.025);
459        assert_eq!(t.fraction_remaining(), 0.975);
460        // Ticking while paused changes nothing
461        t.pause();
462        t.tick(Duration::from_secs_f32(500.0));
463        assert_eq!(t.elapsed_secs(), 0.25);
464        assert_eq!(t.duration(), Duration::from_secs_f32(10.0));
465        assert!(!t.finished());
466        assert!(!t.just_finished());
467        assert_eq!(t.times_finished_this_tick(), 0);
468        assert_eq!(t.mode(), TimerMode::Once);
469        assert_eq!(t.fraction(), 0.025);
470        assert_eq!(t.fraction_remaining(), 0.975);
471        // Tick past the end and make sure elapsed doesn't go past 0.0 and other things update
472        t.unpause();
473        t.tick(Duration::from_secs_f32(500.0));
474        assert_eq!(t.elapsed_secs(), 10.0);
475        assert!(t.finished());
476        assert!(t.just_finished());
477        assert_eq!(t.times_finished_this_tick(), 1);
478        assert_eq!(t.fraction(), 1.0);
479        assert_eq!(t.fraction_remaining(), 0.0);
480        // Continuing to tick when finished should only change just_finished
481        t.tick(Duration::from_secs_f32(1.0));
482        assert_eq!(t.elapsed_secs(), 10.0);
483        assert!(t.finished());
484        assert!(!t.just_finished());
485        assert_eq!(t.times_finished_this_tick(), 0);
486        assert_eq!(t.fraction(), 1.0);
487        assert_eq!(t.fraction_remaining(), 0.0);
488    }
489
490    #[test]
491    fn repeating_timer() {
492        let mut t = Timer::from_seconds(2.0, TimerMode::Repeating);
493        // Tick once, check all attributes
494        t.tick(Duration::from_secs_f32(0.75));
495        assert_eq!(t.elapsed_secs(), 0.75);
496        assert_eq!(t.duration(), Duration::from_secs_f32(2.0));
497        assert!(!t.finished());
498        assert!(!t.just_finished());
499        assert_eq!(t.times_finished_this_tick(), 0);
500        assert_eq!(t.mode(), TimerMode::Repeating);
501        assert_eq!(t.fraction(), 0.375);
502        assert_eq!(t.fraction_remaining(), 0.625);
503        // Tick past the end and make sure elapsed wraps
504        t.tick(Duration::from_secs_f32(1.5));
505        assert_eq!(t.elapsed_secs(), 0.25);
506        assert!(t.finished());
507        assert!(t.just_finished());
508        assert_eq!(t.times_finished_this_tick(), 1);
509        assert_eq!(t.fraction(), 0.125);
510        assert_eq!(t.fraction_remaining(), 0.875);
511        // Continuing to tick should turn off both finished & just_finished for repeating timers
512        t.tick(Duration::from_secs_f32(1.0));
513        assert_eq!(t.elapsed_secs(), 1.25);
514        assert!(!t.finished());
515        assert!(!t.just_finished());
516        assert_eq!(t.times_finished_this_tick(), 0);
517        assert_eq!(t.fraction(), 0.625);
518        assert_eq!(t.fraction_remaining(), 0.375);
519    }
520
521    #[test]
522    fn times_finished_repeating() {
523        let mut t = Timer::from_seconds(1.0, TimerMode::Repeating);
524        assert_eq!(t.times_finished_this_tick(), 0);
525        t.tick(Duration::from_secs_f32(3.5));
526        assert_eq!(t.times_finished_this_tick(), 3);
527        assert_eq!(t.elapsed_secs(), 0.5);
528        assert!(t.finished());
529        assert!(t.just_finished());
530        t.tick(Duration::from_secs_f32(0.2));
531        assert_eq!(t.times_finished_this_tick(), 0);
532    }
533
534    #[test]
535    fn times_finished_this_tick() {
536        let mut t = Timer::from_seconds(1.0, TimerMode::Once);
537        assert_eq!(t.times_finished_this_tick(), 0);
538        t.tick(Duration::from_secs_f32(1.5));
539        assert_eq!(t.times_finished_this_tick(), 1);
540        t.tick(Duration::from_secs_f32(0.5));
541        assert_eq!(t.times_finished_this_tick(), 0);
542    }
543
544    #[test]
545    fn times_finished_this_tick_repeating_zero_duration() {
546        let mut t = Timer::from_seconds(0.0, TimerMode::Repeating);
547        assert_eq!(t.times_finished_this_tick(), 0);
548        assert_eq!(t.elapsed(), Duration::ZERO);
549        assert_eq!(t.fraction(), 1.0);
550        t.tick(Duration::from_secs(1));
551        assert_eq!(t.times_finished_this_tick(), u32::MAX);
552        assert_eq!(t.elapsed(), Duration::ZERO);
553        assert_eq!(t.fraction(), 1.0);
554        t.tick(Duration::from_secs(2));
555        assert_eq!(t.times_finished_this_tick(), u32::MAX);
556        assert_eq!(t.elapsed(), Duration::ZERO);
557        assert_eq!(t.fraction(), 1.0);
558        t.reset();
559        assert_eq!(t.times_finished_this_tick(), 0);
560        assert_eq!(t.elapsed(), Duration::ZERO);
561        assert_eq!(t.fraction(), 1.0);
562    }
563
564    #[test]
565    fn times_finished_this_tick_precise() {
566        let mut t = Timer::from_seconds(0.01, TimerMode::Repeating);
567        let duration = Duration::from_secs_f64(0.333);
568
569        // total duration: 0.333 => 33 times finished
570        t.tick(duration);
571        assert_eq!(t.times_finished_this_tick(), 33);
572        // total duration: 0.666 => 33 times finished
573        t.tick(duration);
574        assert_eq!(t.times_finished_this_tick(), 33);
575        // total duration: 0.999 => 33 times finished
576        t.tick(duration);
577        assert_eq!(t.times_finished_this_tick(), 33);
578        // total duration: 1.332 => 34 times finished
579        t.tick(duration);
580        assert_eq!(t.times_finished_this_tick(), 34);
581    }
582
583    #[test]
584    fn paused() {
585        let mut t = Timer::from_seconds(10.0, TimerMode::Once);
586
587        t.tick(Duration::from_secs_f32(10.0));
588        assert!(t.just_finished());
589        assert!(t.finished());
590        // A paused timer should change just_finished to false after a tick
591        t.pause();
592        t.tick(Duration::from_secs_f32(5.0));
593        assert!(!t.just_finished());
594        assert!(t.finished());
595    }
596
597    #[test]
598    fn paused_repeating() {
599        let mut t = Timer::from_seconds(10.0, TimerMode::Repeating);
600
601        t.tick(Duration::from_secs_f32(10.0));
602        assert!(t.just_finished());
603        assert!(t.finished());
604        // A paused repeating timer should change finished and just_finished to false after a tick
605        t.pause();
606        t.tick(Duration::from_secs_f32(5.0));
607        assert!(!t.just_finished());
608        assert!(!t.finished());
609    }
610}