simple_game_utils/
timing.rs1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3use std::time::Instant;
4
5#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25#[derive(Debug, Clone, PartialEq)]
26pub struct Timer {
27 remaining: f64,
29 reset: f64,
31 looping: bool,
33}
34
35impl Timer {
36 pub fn new_with_delay(delay: f64, duration: f64) -> Self {
42 Self {
43 remaining: delay,
44 reset: duration,
45 looping: true,
46 }
47 }
48
49 pub fn new(duration: f64) -> Self {
55 Self {
56 remaining: 0.0,
57 reset: duration,
58 looping: true,
59 }
60 }
61
62 pub fn new_once(after: f64) -> Self {
65 Self {
66 remaining: after,
67 reset: after,
68 looping: false,
69 }
70 }
71}
72
73impl Timer {
74 #[inline]
76 pub fn update(&mut self, timing: &Timing) -> bool {
77 self.update_secs(timing.fixed_time_step)
78 }
79
80 pub fn update_secs(&mut self, delta: f64) -> bool {
83 self.remaining -= delta;
84 let triggered = self.remaining <= 0.0;
85 if triggered && self.looping {
86 self.remaining = self.reset;
87 }
88 triggered
89 }
90
91 #[inline]
94 pub fn reset(&mut self) {
95 self.remaining = self.reset;
96 }
97
98 #[inline]
100 pub fn has_triggered(&self) -> bool {
101 self.remaining <= 0.0
102 }
103
104 #[inline]
106 pub fn trigger(&mut self) {
107 self.remaining = 0.0;
108 }
109
110 #[inline]
112 pub fn delay(&mut self, seconds: f64) {
113 self.remaining += seconds;
114 }
115}
116
117#[derive(Debug, Clone, PartialEq)]
119pub struct Timing {
120 pub delta: f64,
122 pub started_at: Instant,
124 pub now: Instant,
126 pub last: Instant,
128 pub updates: usize,
130 pub renders: usize,
132 pub accumulated_time: f64,
133 max_render_time: f64,
134 pub fixed_time_step: f64,
136 pub fixed_time_step_f32: f32,
138 pub stats: Stats,
140}
141
142#[derive(Debug, Clone, Eq, PartialEq)]
143pub struct Stats {
144 pub fps: usize,
146 pub last_frame_count: usize,
148 pub last_frame_check: Instant,
150}
151
152impl Timing {
153 pub fn new(speed: usize) -> Timing {
154 Timing {
155 delta: 0.0,
156 started_at: Instant::now(),
157 now: Instant::now(),
158 last: Instant::now(),
159 updates: 0,
160 renders: 0,
161 accumulated_time: 0.0,
162 max_render_time: 0.1,
163 fixed_time_step: 1.0 / (speed as f64),
164 fixed_time_step_f32: 1.0 / (speed as f32),
165 stats: Stats {
166 fps: 0,
167 last_frame_count: 0,
168 last_frame_check: Instant::now(),
169 },
170 }
171 }
172
173 pub fn update_fps(&mut self) {
174 if self
175 .now
176 .duration_since(self.stats.last_frame_check)
177 .as_secs_f32()
178 >= 1.0
179 {
180 self.stats.fps = self.renders - self.stats.last_frame_count;
181 self.stats.last_frame_check = self.now;
182 self.stats.last_frame_count = self.renders;
183 }
184 }
185
186 pub fn update(&mut self) {
187 self.now = Instant::now();
188 self.delta = self.now.duration_since(self.last).as_secs_f64();
189 self.accumulated_time += self.delta;
190 if self.delta > self.max_render_time {
191 self.delta = self.max_render_time;
192 }
193 }
194}
195
196#[cfg(test)]
197mod test {
198 use crate::timing::Timer;
199
200 #[test]
201 fn basic_test_delayed() {
202 let mut timer = Timer::new_with_delay(1.0, 1.0);
203 assert!(!timer.update_secs(0.4));
204 assert!(!timer.update_secs(0.4));
205 assert!(timer.update_secs(0.4));
206 assert!(!timer.has_triggered());
207 }
208
209 #[test]
210 fn basic_test() {
211 let mut timer = Timer::new(0.5);
212 assert!(timer.has_triggered());
213 timer.reset();
214 assert!(!timer.has_triggered());
215 assert!(!timer.update_secs(0.4));
216 assert!(timer.update_secs(0.4));
217 assert!(!timer.has_triggered());
218 }
219}