bevy_time/
timer.rs

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