gameloop_timing/
tickloop.rs1use super::*;
4
5pub struct TickLoopState {
7 start: Instant,
9
10 ticks_per_second: u32,
12
13 tick_duration: Duration,
15
16 tock_duration: Duration,
18
19 max_frameskip: i32,
21
22 loops: i32,
24
25 next_game_tick: Instant,
27
28 next_game_tock: Instant,
30
31 last_tick_time: Instant,
33
34 last_tock_time: Instant,
36
37 tick_count: u32,
39
40 total_ticks: u64,
42
43 total_tocks: u64,
45}
46
47#[derive(Debug)]
49pub struct TickLoopEvent {
50 pub target_tickrate: u32,
52
53 pub time: Instant,
55
56 pub duration: Duration,
58
59 pub ticks: u64,
61}
62
63#[derive(Debug)]
65pub struct TockLoopEvent {
66 pub target_tickrate: u32,
68
69 pub time: Instant,
71
72 pub duration: Duration,
74
75 pub ticks: u64,
77
78 pub tocks: u64,
80
81 pub last_tock: Instant,
83
84 pub average_tickrate: f64,
86}
87
88impl TickLoopState {
89 pub fn new(ticks_per_second: u32) -> Self {
91 Self {
92 start: Instant::now(),
93 ticks_per_second,
94 tick_duration: Duration::from_secs(1) / ticks_per_second,
95 tock_duration: Duration::from_secs(1),
96 max_frameskip: 1,
97 loops: 0,
98 next_game_tick: Instant::now(),
99 next_game_tock: Instant::now(),
100 last_tick_time: Instant::now(),
101 last_tock_time: Instant::now(),
102 tick_count: 0,
103 total_ticks: 0,
104 total_tocks: 0,
105 }
106 }
107
108 pub fn pre(&mut self) {
110 self.loops = 0;
111 }
112
113 pub fn tick<F: FnOnce(&mut TickLoopEvent)>(&mut self, current_time: Instant, function: F) -> bool {
115
116 if (current_time > self.next_game_tick) && (self.loops < self.max_frameskip) {
117 function(&mut TickLoopEvent {
118 target_tickrate: self.ticks_per_second,
119 time: current_time,
120 duration: self.tick_duration,
121 ticks: self.total_ticks,
122 });
123
124 self.last_tick_time = current_time;
125 self.next_game_tick += self.tick_duration;
126 self.loops += 1;
127 self.tick_count += 1;
128 self.total_ticks += 1;
129
130 return true;
131 }
132
133 false
134 }
135
136 pub fn tock<F: FnOnce(&mut TockLoopEvent)>(&mut self, current_time: Instant, function: F) -> bool {
138
139 let time_since_tock = current_time.duration_since(self.last_tock_time).as_secs_f64();
140
141 if self.next_game_tock <= current_time {
142 let hertz_avg = self.tick_count as f64 / time_since_tock;
143
144 function(&mut TockLoopEvent {
145 target_tickrate: self.ticks_per_second,
146 time: current_time,
147 duration: self.tick_duration,
148 last_tock: self.last_tock_time,
149 average_tickrate: hertz_avg,
150 ticks: self.total_ticks,
151 tocks: self.total_tocks,
152 });
153
154 self.tick_count = 0;
155 self.total_tocks += 1;
156 self.last_tock_time = current_time;
157 self.next_game_tock = current_time + self.tock_duration;
158 return true;
159 }
160
161 false
162 }
163
164 pub fn interpolation(&self, current_time: Instant) -> f64 {
166 let delta = current_time - self.next_game_tick;
167 (delta + self.tick_duration).as_secs_f64() / self.tick_duration.as_secs_f64()
168 }
169
170 pub fn get_minimum_tick_duration(&self) -> Duration {
172 self.tick_duration
173 }
174
175 pub fn get_start(&self) -> Instant {
177 self.start
178 }
179}