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:
Gered 2023-02-03 17:55:11 -05:00
parent 3d7c4f63ea
commit da66e10bbd
2 changed files with 97 additions and 0 deletions

View 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(())
}

View file

@ -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;