1#![no_std]
2#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
3#![warn(missing_docs)]
4
5use core::time::Duration;
6
7#[derive(Clone, Debug)]
9pub struct GameLoop {
10 target_frame_time: Duration,
11 max_frame_time: Duration,
12 accumulated_time: Duration,
13
14 total_num_updates: u64,
15 total_time_passed: Duration,
16}
17
18impl GameLoop {
19 #[inline]
21 pub fn new(target_frame_time: Duration, max_frame_time: Duration) -> Self {
22 Self {
23 target_frame_time,
24 max_frame_time,
25 accumulated_time: Duration::ZERO,
26
27 total_num_updates: 0,
28 total_time_passed: Duration::ZERO,
29 }
30 }
31
32 #[inline]
34 pub fn new_with_fps(fps: u32, max_frame_time: Duration) -> Self {
35 Self::new(Duration::from_secs_f64(1. / fps as f64), max_frame_time)
36 }
37
38 #[inline]
40 pub fn set_target_frame_time(&mut self, time: Duration) {
41 self.target_frame_time = time;
42 }
43
44 #[inline]
46 pub fn set_fps(&mut self, fps: u32) {
47 self.target_frame_time = Duration::from_secs_f64(1. / fps as f64);
48 }
49
50 #[inline]
53 pub fn set_max_frame_time(&mut self, time: Duration) {
54 self.max_frame_time = time;
55 }
56
57 pub fn update(&mut self, elapsed: Duration) -> UpdateResult {
76 self.total_time_passed += elapsed;
77
78 self.accumulated_time += if elapsed > self.max_frame_time {
79 self.max_frame_time
80 } else {
81 elapsed
82 };
83
84 let mut num_updates = 0;
85
86 while self.accumulated_time >= self.target_frame_time {
87 self.accumulated_time -= self.target_frame_time;
88 num_updates += 1;
89 }
90
91 self.total_num_updates += num_updates;
92
93 let blending_factor =
94 self.accumulated_time.as_secs_f64() / self.target_frame_time.as_secs_f64();
95
96 UpdateResult {
97 num_updates,
98 total_num_updates: self.total_num_updates,
99
100 frame_time: self.target_frame_time,
101 blending_factor,
102
103 total_time_passed: self.total_time_passed,
104
105 exit: false,
106 }
107 }
108}
109
110#[derive(Clone, Debug)]
112pub struct UpdateResult {
113 pub num_updates: u64,
115 pub total_num_updates: u64,
117
118 pub frame_time: Duration,
120 pub blending_factor: f64,
122
123 pub total_time_passed: Duration,
126
127 pub exit: bool,
130}
131
132impl UpdateResult {
133 #[inline]
138 pub fn run<F>(mut self, mut func: F) -> Self
139 where
140 F: FnMut(&mut Self),
141 {
142 for _i in 0..self.num_updates {
143 (func)(&mut self);
144
145 if self.exit {
146 break;
147 }
148 }
149
150 self
151 }
152
153 #[inline]
158 pub fn run_result<F, E>(mut self, mut func: F) -> Result<Self, E>
159 where
160 F: FnMut(&mut Self) -> Result<(), E>,
161 {
162 for _i in 0..self.num_updates {
163 (func)(&mut self)?;
164
165 if self.exit {
166 break;
167 }
168 }
169
170 Ok(self)
171 }
172}