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}