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}