quicksilver/timer.rs
1use core::num::NonZeroUsize;
2use instant::Instant;
3use std::time::Duration;
4
5#[derive(Debug, Clone)]
6/// A timer that you can use to fix the time between actions, for example updates or draw calls.
7///
8/// See the article [Fix Your Timestep](https://gafferongames.com/post/fix_your_timestep/) for more
9/// on how to use timers to ensure framerate-independence.
10pub struct Timer {
11 period: Duration,
12 init: Instant,
13}
14
15impl Timer {
16 /// Create a timer that ticks n many times per second
17 pub fn time_per_second(times: f32) -> Timer {
18 Timer::with_duration(Duration::from_secs_f32(1.0 / times))
19 }
20
21 /// Create a timer with a given period (time between ticks)
22 pub fn with_duration(period: Duration) -> Timer {
23 Timer {
24 period,
25 init: Instant::now(),
26 }
27 }
28
29 /// Look if the time has elapsed and if so, starts the countdown for the next tick.
30 ///
31 /// You can use a while loop instead of an if to catch up in the event that you were late. Each
32 /// tick will only 'consume' one period worth of time.
33 pub fn tick(&mut self) -> bool {
34 if self.init.elapsed() >= self.period {
35 self.init += self.period;
36 true
37 } else {
38 false
39 }
40 }
41
42 /// Similar to Self::tick() but tells you how many ticks have passed, rather than just if a tick has passed.
43 ///
44 /// This is useful in situations where catching up isn't needed or possible, like rendering to
45 /// the screen. If you've missed rendering three frames, there's no point in drawing them now:
46 /// just render the current state and move on.
47 pub fn exhaust(&mut self) -> Option<NonZeroUsize> {
48 let mut count = 0;
49 while self.tick() {
50 count += 1;
51 }
52 NonZeroUsize::new(count)
53 }
54
55 /// Resets the timer to count from this moment.
56 ///
57 /// This is the same as creating a new Timer with the same period
58 pub fn reset(&mut self) {
59 self.init = Instant::now();
60 }
61
62 /// Gets the time in between ticks
63 pub fn period(&self) -> Duration {
64 self.period
65 }
66
67 /// How much time has passed since the timer was last ticked
68 pub fn elapsed(&self) -> Duration {
69 self.init.elapsed()
70 }
71
72 /// Look how much time is still left before its time for next tick.
73 pub fn remaining(&self) -> Option<Duration> {
74 self.period.checked_sub(self.init.elapsed())
75 }
76
77 /// Look how late you are with calling Timer::tick() if you would call it right now
78 pub fn late_by(&self) -> Option<Duration> {
79 self.init.elapsed().checked_sub(self.period)
80 }
81}