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