1use crate::*;
2
3pub struct GameLoop<G, T: TimeTrait, W> {
4 pub game: G,
5 pub updates_per_second: u32,
6 pub max_frame_time: f64,
7 pub exit_next_iteration: bool,
8 pub window: W,
9 pub window_occluded: bool,
10
11 fixed_time_step: f64,
12 number_of_updates: u64,
13 number_of_renders: u64,
14 last_frame_time: f64,
15 running_time: f64,
16 accumulated_time: f64,
17 blending_factor: f64,
18 previous_instant: T,
19 current_instant: T,
20}
21
22impl<G, T: TimeTrait, W> GameLoop<G, T, W> {
23 pub fn new(game: G, updates_per_second: u32, max_frame_time: f64, window: W) -> Self {
24 Self {
25 game,
26 updates_per_second,
27 max_frame_time,
28 window,
29 window_occluded: false,
30 exit_next_iteration: false,
31
32 fixed_time_step: 1.0 / updates_per_second as f64,
33 number_of_updates: 0,
34 number_of_renders: 0,
35 running_time: 0.0,
36 accumulated_time: 0.0,
37 blending_factor: 0.0,
38 previous_instant: T::now(),
39 current_instant: T::now(),
40 last_frame_time: 0.0,
41 }
42 }
43
44 pub fn next_frame<U, R>(&mut self, mut update: U, mut render: R) -> bool
45 where U: FnMut(&mut GameLoop<G, T, W>),
46 R: FnMut(&mut GameLoop<G, T, W>),
47 {
48 let g = self;
49
50 if g.exit_next_iteration { return false; }
51
52 g.current_instant = T::now();
53
54 let mut elapsed = g.current_instant.sub(&g.previous_instant);
55 if elapsed > g.max_frame_time { elapsed = g.max_frame_time; }
56
57 g.last_frame_time = elapsed;
58 g.running_time += elapsed;
59 g.accumulated_time += elapsed;
60
61 while g.accumulated_time >= g.fixed_time_step {
62 update(g);
63
64 g.accumulated_time -= g.fixed_time_step;
65 g.number_of_updates += 1;
66 }
67
68 g.blending_factor = g.accumulated_time / g.fixed_time_step;
69
70 if g.window_occluded && T::supports_sleep() {
71 T::sleep(g.fixed_time_step);
72 } else {
73 render(g);
74 g.number_of_renders += 1;
75 }
76
77 g.previous_instant = g.current_instant;
78
79 true
80 }
81
82 pub fn re_accumulate(&mut self) {
83 let g = self;
84
85 g.current_instant = T::now();
86
87 let prev_elapsed = g.last_frame_time;
88 let new_elapsed = g.current_instant.sub(&g.previous_instant);
89
90 let delta = new_elapsed - prev_elapsed;
91
92 g.running_time += delta;
96 g.accumulated_time += delta;
97
98 g.blending_factor = g.accumulated_time / g.fixed_time_step;
99 }
100
101 pub fn exit(&mut self) {
102 self.exit_next_iteration = true;
103 }
104
105 pub fn set_updates_per_second(&mut self, new_updates_per_second: u32) {
106 self.updates_per_second = new_updates_per_second;
107 self.fixed_time_step = 1.0 / new_updates_per_second as f64;
108 }
109
110 pub fn fixed_time_step(&self) -> f64 {
111 self.fixed_time_step
112 }
113
114 pub fn number_of_updates(&self) -> u64 {
115 self.number_of_updates
116 }
117
118 pub fn number_of_renders(&self) -> u64 {
119 self.number_of_renders
120 }
121
122 pub fn last_frame_time(&self) -> f64 {
123 self.last_frame_time
124 }
125
126 pub fn running_time(&self) -> f64 {
127 self.running_time
128 }
129
130 pub fn accumulated_time(&self) -> f64 {
131 self.accumulated_time
132 }
133
134 pub fn blending_factor(&self) -> f64 {
135 self.blending_factor
136 }
137
138 pub fn previous_instant(&self) -> T {
139 self.previous_instant
140 }
141
142 pub fn current_instant(&self) -> T {
143 self.current_instant
144 }
145}