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}