initial main loop and game state/context boilerplate helper things
work in progress stuff that will be tweaked as i convert things over to use this and, i assume, inevitably encounter problems and/or discover some better ways to do it
This commit is contained in:
parent
3d7c4f63ea
commit
da66e10bbd
96
libretrogd/src/base/mod.rs
Normal file
96
libretrogd/src/base/mod.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
//! Optional, extra types and helpers that can be used to get game's main loop boilerplate up and
|
||||
//! running quicker.
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::events::*;
|
||||
use crate::states::*;
|
||||
use crate::system::*;
|
||||
|
||||
pub trait AppState {
|
||||
fn system(&self) -> &System;
|
||||
fn system_mut(&mut self) -> &mut System;
|
||||
}
|
||||
|
||||
pub trait AppStateWithFrameTiming: AppState {
|
||||
fn delta(&self) -> f32;
|
||||
fn set_delta(&mut self, delta: f32);
|
||||
|
||||
fn update_frame_delta(&mut self, last_ticks: u64) -> u64 {
|
||||
let ticks = self.system().ticks();
|
||||
let tick_frequency = self.system().tick_frequency();
|
||||
let elapsed = ticks - last_ticks;
|
||||
self.set_delta((elapsed as f64 / tick_frequency as f64) as f32);
|
||||
ticks
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AppStateWithEvents<EventType>: AppState {
|
||||
fn event_publisher(&mut self) -> &mut EventPublisher<EventType>;
|
||||
}
|
||||
|
||||
pub trait SupportSystems {}
|
||||
|
||||
pub trait SupportSystemsWithEvents<EventType, ContextType>: SupportSystems
|
||||
where
|
||||
ContextType: AppStateWithEvents<EventType>,
|
||||
{
|
||||
fn event_listeners(&mut self) -> &mut EventListeners<EventType, ContextType>;
|
||||
|
||||
fn do_events(&mut self, context: &mut ContextType) {
|
||||
self.event_listeners().take_queue_from(context.event_publisher());
|
||||
self.event_listeners().dispatch_queue(context);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct App<StateType, SupportType> {
|
||||
pub state: StateType,
|
||||
pub support: SupportType,
|
||||
}
|
||||
|
||||
impl<StateType, SupportType> App<StateType, SupportType> {
|
||||
pub fn new(state: StateType, support: SupportType) -> Self {
|
||||
App { state, support }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MainLoopError {
|
||||
#[error("States error: {0}")]
|
||||
StateError(#[from] StateError),
|
||||
|
||||
#[error("System error: {0}")]
|
||||
SystemError(#[from] SystemError),
|
||||
}
|
||||
|
||||
pub fn main_loop<StateType, SupportType, State>(
|
||||
mut app: App<StateType, SupportType>,
|
||||
initial_state: State,
|
||||
) -> Result<(), MainLoopError>
|
||||
where
|
||||
StateType: AppStateWithFrameTiming,
|
||||
SupportType: SupportSystems,
|
||||
State: GameState<StateType> + 'static,
|
||||
{
|
||||
let mut states = States::new();
|
||||
states.push(initial_state)?;
|
||||
|
||||
let mut is_running = true;
|
||||
let mut last_ticks = app.state.system().ticks();
|
||||
|
||||
while is_running && !states.is_empty() {
|
||||
app.state.system_mut().do_events_with(|event| match event {
|
||||
SystemEvent::Quit => {
|
||||
is_running = false;
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
|
||||
last_ticks = app.state.update_frame_delta(last_ticks);
|
||||
states.update(&mut app.state)?;
|
||||
states.render(&mut app.state);
|
||||
app.state.system_mut().display()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -2,6 +2,7 @@ extern crate core;
|
|||
extern crate sdl2;
|
||||
|
||||
pub mod audio;
|
||||
pub mod base;
|
||||
pub mod entities;
|
||||
pub mod events;
|
||||
pub mod graphics;
|
||||
|
|
Loading…
Reference in a new issue