1use std::time::Duration;
2use web_time::Instant;
3
4use crate::{
5 game::ButteryGame,
6 key_event::KeyEvent,
7 renderer::{ButteryRenderer, FallbackRenderer},
8 windowing::ButteryWindowingSystem,
9 world_model::ButteryWorldModel,
10};
11
12pub enum ButteryEvent {
13 Init,
14 Update,
15 KeyPress(String),
16}
17
18pub struct ButteryEngineState {
19 pub renderer: Box<dyn ButteryRenderer>,
20 last_frame_time: Instant,
21 pub delta_time: f32,
22 pub world_model: ButteryWorldModel,
23}
24
25pub struct ButteryEngine {
26 pub state: ButteryEngineState,
27 pub game: Box<dyn ButteryGame>,
28}
29
30impl ButteryEngine {
31 pub fn run(
32 windowing_system: Box<dyn ButteryWindowingSystem>,
33 game: Box<dyn ButteryGame>,
34 ) -> anyhow::Result<()> {
35 let engine = Self {
36 game,
37 state: ButteryEngineState {
38 renderer: Box::new(FallbackRenderer {}),
39 delta_time: 1.0 / 60.0,
40 last_frame_time: web_time::Instant::now(),
41 world_model: ButteryWorldModel::default(),
42 },
43 };
44
45 windowing_system.run(engine)
46 }
47
48 pub fn on_init(&mut self) {
49 self.game.on_init(&mut self.state);
50 }
51
52 pub fn on_update(&mut self) {
53 for object in self.state.world_model.objects.iter_mut() {
54 object.update();
55 }
56
57 self.game.on_update(&mut self.state);
58
59 self.state.renderer.on_update(&self.state.world_model);
60 }
61
62 pub fn on_key_event(&mut self, key_event: KeyEvent) {
63 self.game.on_key_event(&mut self.state, key_event);
64 }
65
66 pub fn calc_delta_time(&mut self) {
67 let now = web_time::Instant::now();
68 let delta = now
69 .checked_duration_since(self.state.last_frame_time)
70 .unwrap_or(Duration::from_millis(16))
71 .as_secs_f32();
72
73 self.state.last_frame_time = now;
74 self.state.delta_time = delta;
75 }
76}