#![deny(missing_docs)]
pub use game_clock::*;
pub use game_state_machine::*;
use spin_sleep::LoopHelper;
pub struct Engine<SD, F: Fn(&mut SD, &Time)> {
loop_helper: LoopHelper,
pub state_machine: StateMachine<SD>,
pub state_data: SD,
pub time: Time,
post_update: F,
}
impl<SD, F: Fn(&mut SD, &Time)> Engine<SD, F> {
pub fn new<I: State<SD> + 'static>(
init_state: I,
mut init_state_data: SD,
post_update: F,
max_fps: f32,
) -> Self {
let loop_helper = LoopHelper::builder().build_with_target_rate(max_fps);
let mut state_machine = StateMachine::default();
let time = Time::default();
state_machine.push(Box::new(init_state), &mut init_state_data);
Self {
loop_helper,
state_machine,
state_data: init_state_data,
time,
post_update,
}
}
pub fn engine_frame(&mut self, sleep: bool) -> bool {
if sleep {
let delta = self.loop_helper.loop_start();
{
self.time.advance_frame(delta);
}
}
self.state_machine.update(&mut self.state_data);
if sleep {
self.loop_helper.loop_sleep();
}
(self.post_update)(&mut self.state_data, &self.time);
self.state_machine.is_running()
}
pub fn engine_loop(&mut self) {
while self.engine_frame(true) {}
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn test_loop() {
struct MyState;
impl State<i32> for MyState {
fn update(&mut self, state_data: &mut i32) -> StateTransition<i32> {
*state_data += 1;
StateTransition::Quit
}
}
Engine::new(
MyState,
0,
|s, _| {
*s += 1;
assert_eq!(*s, 2);
},
1000.0,
)
.engine_loop();
}
}