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