1#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
21pub struct Time {
22 dt: f32,
24 raw_dt: f32,
26 elapsed: f64,
28 frame_count: u64,
30 time_scale: f32,
32 max_dt: f32,
34}
35
36const DEFAULT_MAX_DT: f32 = 1.0 / 20.0;
38
39impl Time {
40 pub fn new() -> Self {
41 Self {
42 dt: 0.0,
43 raw_dt: 0.0,
44 elapsed: 0.0,
45 frame_count: 0,
46 time_scale: 1.0,
47 max_dt: DEFAULT_MAX_DT,
48 }
49 }
50
51 pub fn update(&mut self, raw_dt: f32) {
54 self.raw_dt = raw_dt.max(0.0); self.dt = (self.raw_dt * self.time_scale).min(self.max_dt);
56 self.elapsed += self.dt as f64;
57 self.frame_count += 1;
58 }
59
60 #[inline]
65 pub fn dt(&self) -> f32 {
66 self.dt
67 }
68
69 #[inline]
72 pub fn raw_dt(&self) -> f32 {
73 self.raw_dt
74 }
75
76 #[inline]
79 pub fn elapsed(&self) -> f64 {
80 self.elapsed
81 }
82
83 #[inline]
85 pub fn frame(&self) -> u64 {
86 self.frame_count
87 }
88
89 #[inline]
91 pub fn time_scale(&self) -> f32 {
92 self.time_scale
93 }
94
95 #[inline]
97 pub fn fps(&self) -> f32 {
98 if self.raw_dt > 0.0 {
99 1.0 / self.raw_dt
100 } else {
101 0.0
102 }
103 }
104
105 pub fn set_time_scale(&mut self, scale: f32) {
109 self.time_scale = scale.max(0.0);
110 }
111
112 pub fn set_max_dt(&mut self, max: f32) {
114 self.max_dt = max.max(0.001); }
116}
117
118impl Default for Time {
119 fn default() -> Self {
120 Self::new()
121 }
122}
123
124#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
138pub struct PhysicsTime {
139 fixed_dt: f32,
141 accumulator: f32,
143 max_accumulator: f32,
145 step_count: u64,
147 physics_elapsed: f64,
149 alpha: f32,
152}
153
154impl PhysicsTime {
155 pub fn new(hz: u32) -> Self {
157 let fixed_dt = 1.0 / hz as f32;
158 Self {
159 fixed_dt,
160 accumulator: 0.0,
161 max_accumulator: fixed_dt * 8.0, step_count: 0,
163 physics_elapsed: 0.0,
164 alpha: 0.0,
165 }
166 }
167
168 pub fn accumulate(&mut self, render_dt: f32) {
171 self.accumulator += render_dt;
172 if self.accumulator > self.max_accumulator {
174 self.accumulator = self.max_accumulator;
175 }
176 }
177
178 #[inline]
180 pub fn should_step(&self) -> bool {
181 self.accumulator >= self.fixed_dt
182 }
183
184 pub fn consume_step(&mut self) {
187 self.accumulator -= self.fixed_dt;
188 self.step_count += 1;
189 self.physics_elapsed += self.fixed_dt as f64;
190 }
191
192 pub fn compute_alpha(&mut self) {
195 self.alpha = self.accumulator / self.fixed_dt;
196 }
197
198 #[inline]
202 pub fn fixed_dt(&self) -> f32 {
203 self.fixed_dt
204 }
205
206 #[inline]
209 pub fn alpha(&self) -> f32 {
210 self.alpha
211 }
212
213 #[inline]
215 pub fn step_count(&self) -> u64 {
216 self.step_count
217 }
218
219 #[inline]
221 pub fn physics_elapsed(&self) -> f64 {
222 self.physics_elapsed
223 }
224
225 #[inline]
227 pub fn accumulator(&self) -> f32 {
228 self.accumulator
229 }
230
231 pub fn set_hz(&mut self, hz: u32) {
235 self.fixed_dt = 1.0 / hz.max(1) as f32;
236 self.max_accumulator = self.fixed_dt * 8.0;
237 }
238}
239
240impl Default for PhysicsTime {
241 fn default() -> Self {
242 Self::new(60) }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn test_basic_update() {
252 let mut time = Time::new();
253 time.update(0.016);
254
255 assert!((time.dt() - 0.016).abs() < 0.0001);
256 assert!((time.raw_dt() - 0.016).abs() < 0.0001);
257 assert!((time.elapsed() - 0.016).abs() < 0.001);
258 assert_eq!(time.frame(), 1);
259 }
260
261 #[test]
262 fn test_dt_clamp() {
263 let mut time = Time::new();
264 time.update(1.0); assert!(time.dt() <= DEFAULT_MAX_DT + 0.0001);
267 assert!((time.raw_dt() - 1.0).abs() < 0.0001);
268 }
269
270 #[test]
271 fn test_negative_dt_clamped_to_zero() {
272 let mut time = Time::new();
273 time.update(-0.5);
274
275 assert_eq!(time.dt(), 0.0);
276 assert_eq!(time.raw_dt(), 0.0);
277 }
278
279 #[test]
280 fn test_time_scale() {
281 let mut time = Time::new();
282 time.set_time_scale(0.5);
283 time.update(0.016);
284
285 assert!((time.dt() - 0.008).abs() < 0.0001); assert!((time.raw_dt() - 0.016).abs() < 0.0001);
287 }
288
289 #[test]
290 fn test_time_scale_zero_is_pause() {
291 let mut time = Time::new();
292 time.set_time_scale(0.0);
293 time.update(0.016);
294
295 assert_eq!(time.dt(), 0.0);
296 assert_eq!(time.elapsed(), 0.0);
297 assert_eq!(time.frame(), 1); }
299
300 #[test]
301 fn test_elapsed_accumulates() {
302 let mut time = Time::new();
303 for _ in 0..100 {
304 time.update(0.01);
305 }
306
307 assert!((time.elapsed() - 1.0).abs() < 0.01);
308 assert_eq!(time.frame(), 100);
309 }
310
311 #[test]
312 fn test_fps() {
313 let mut time = Time::new();
314 time.update(1.0 / 60.0);
315 assert!((time.fps() - 60.0).abs() < 1.0);
316
317 time.update(0.0);
318 assert_eq!(time.fps(), 0.0); }
320
321 #[test]
322 fn test_custom_max_dt() {
323 let mut time = Time::new();
324 time.set_max_dt(1.0 / 10.0); time.update(0.5);
326
327 assert!((time.dt() - 0.1).abs() < 0.0001); }
329
330 #[test]
331 fn test_serde_derive() {
332 let mut time = Time::new();
334 time.update(0.016);
335 time.update(0.016);
336
337 let cloned = time;
339 assert_eq!(cloned.frame(), time.frame());
340 assert!((cloned.elapsed() - time.elapsed()).abs() < 0.001);
341 }
342
343 #[test]
346 fn test_physics_time_basic_step() {
347 let mut pt = PhysicsTime::new(60);
348 assert!(!pt.should_step()); pt.accumulate(1.0 / 60.0); assert!(pt.should_step());
352
353 pt.consume_step();
354 assert!(!pt.should_step());
355 assert_eq!(pt.step_count(), 1);
356 }
357
358 #[test]
359 fn test_physics_time_multiple_steps() {
360 let mut pt = PhysicsTime::new(60);
361 let fixed_dt = pt.fixed_dt();
362 pt.accumulate(fixed_dt * 3.5);
364
365 let mut steps = 0;
366 while pt.should_step() {
367 pt.consume_step();
368 steps += 1;
369 }
370 assert_eq!(steps, 3);
371 assert_eq!(pt.step_count(), 3);
372 }
373
374 #[test]
375 fn test_physics_time_spiral_of_death() {
376 let mut pt = PhysicsTime::new(60);
377 pt.accumulate(1.0);
379
380 let mut steps = 0;
381 while pt.should_step() {
382 pt.consume_step();
383 steps += 1;
384 }
385 assert!(
386 steps <= 8,
387 "Spiral koruması: max 8 adım, bulundu: {}",
388 steps
389 );
390 }
391
392 #[test]
393 fn test_physics_time_alpha() {
394 let mut pt = PhysicsTime::new(60);
395 let fixed_dt = 1.0 / 60.0;
396
397 pt.accumulate(fixed_dt * 1.5);
399 pt.consume_step(); pt.compute_alpha();
401
402 assert!(
404 (pt.alpha() - 0.5).abs() < 0.01,
405 "Alpha ≈ 0.5: {}",
406 pt.alpha()
407 );
408 }
409
410 #[test]
411 fn test_physics_time_elapsed() {
412 let mut pt = PhysicsTime::new(60);
413 for _ in 0..60 {
414 pt.accumulate(1.0 / 60.0);
415 while pt.should_step() {
416 pt.consume_step();
417 }
418 }
419 assert!((pt.physics_elapsed() - 1.0).abs() < 0.001);
421 }
422
423 #[test]
424 fn test_physics_time_set_hz() {
425 let mut pt = PhysicsTime::new(60);
426 pt.set_hz(120);
427 assert!((pt.fixed_dt() - 1.0 / 120.0).abs() < 1e-6);
428 }
429}