use crate::gui::message::UiMessage;
use crate::utils::log::{Log, MessageKind};
use crate::{
core::instant::Instant,
engine::{error::EngineError, Engine},
event::{DeviceEvent, DeviceId, Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
utils::translate_event,
window::WindowBuilder,
};
#[doc(hidden)]
pub mod prelude {
pub use super::{Framework, GameState};
}
pub trait GameState: 'static {
fn init(engine: &mut Engine) -> Self
where
Self: Sized;
fn on_tick(&mut self, _engine: &mut Engine, _dt: f32, _control_flow: &mut ControlFlow) {}
fn on_ui_message(&mut self, _engine: &mut Engine, _message: UiMessage) {}
fn on_device_event(&mut self, _engine: &mut Engine, _device_id: DeviceId, _event: DeviceEvent) {
}
fn on_window_event(&mut self, _engine: &mut Engine, _event: WindowEvent) {}
fn on_exit(&mut self, _engine: &mut Engine) {}
}
pub struct Framework<State: GameState> {
engine: Engine,
title: String,
event_loop: EventLoop<()>,
state: State,
}
impl<State: GameState> Framework<State> {
pub fn new() -> Result<Self, EngineError> {
let event_loop = EventLoop::new();
let window_builder = WindowBuilder::new().with_title("Game").with_resizable(true);
let mut engine = Engine::new(window_builder, &event_loop, false)?;
Ok(Self {
title: "Game".to_owned(),
state: State::init(&mut engine),
engine,
event_loop,
})
}
#[must_use]
pub fn title<S: AsRef<str>>(mut self, title: S) -> Self {
self.title = title.as_ref().to_owned();
self
}
pub fn run(self) -> ! {
let mut engine = self.engine;
engine.get_window().set_title(&self.title);
let mut state = self.state;
let clock = Instant::now();
let fixed_timestep = 1.0 / 60.0;
let mut elapsed_time = 0.0;
self.event_loop
.run(move |event, _, control_flow| match event {
Event::MainEventsCleared => {
let mut dt = clock.elapsed().as_secs_f32() - elapsed_time;
while dt >= fixed_timestep {
dt -= fixed_timestep;
elapsed_time += fixed_timestep;
state.on_tick(&mut engine, fixed_timestep, control_flow);
engine.update(fixed_timestep);
}
while let Some(ui_msg) = engine.user_interface.poll_message() {
state.on_ui_message(&mut engine, ui_msg);
}
engine.get_window().request_redraw();
}
Event::RedrawRequested(_) => {
engine.render().unwrap();
}
Event::WindowEvent { event, .. } => {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(size) => {
if let Err(e) = engine.set_frame_size(size.into()) {
Log::writeln(
MessageKind::Error,
format!("Unable to set frame size: {:?}", e),
);
}
}
_ => (),
}
if let Some(os_event) = translate_event(&event) {
engine.user_interface.process_os_event(&os_event);
}
state.on_window_event(&mut engine, event);
}
Event::DeviceEvent { device_id, event } => {
state.on_device_event(&mut engine, device_id, event);
}
Event::LoopDestroyed => state.on_exit(&mut engine),
_ => *control_flow = ControlFlow::Poll,
})
}
}