diff --git a/src/engine.rs b/src/engine.rs index 4a960c0..bf360ac 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,5 +1,5 @@ use std::any::{Any, TypeId}; -use std::collections::HashMap; +use std::rc::Rc; use std::time::Duration; use sdl2::{ @@ -40,33 +40,34 @@ macro_rules! impl_from_T_for_Error { }; } -impl_from_T_for_Error!(String, WindowBuildError, IntegerOrSdlError); +impl_from_T_for_Error!(String, WindowBuildError, IntegerOrSdlError, &str); -pub struct Entity(u64, Vec>); +pub type Id = u64; + +pub struct Entity(Id, Vec>); pub trait Component { fn inner_type_id(&self) -> TypeId; fn as_any(&mut self) -> &mut dyn Any; } -pub struct Sprite { - path: std::path::PathBuf, -} +#[derive(Clone, Copy)] +pub struct Sprite(Id); pub struct Context<'context, 'game> where 'game: 'context, { - id_counter: &'context mut u64, + id_counter: &'context mut Id, canvas: &'context mut Canvas, texture_creator: *const TextureCreator, entities: &'context mut Vec, - systems: &'context mut Vec>, - textures: &'context mut HashMap>, + systems: &'context mut Vec>, + textures: &'context mut Vec<(Id, Texture<'game>)>, } impl<'context, 'game> Context<'context, 'game> { - pub fn entities_with_component(&self) -> Vec { + pub fn entities_with_component(&self) -> Vec { let entity_type_id = TypeId::of::(); self.entities .iter() @@ -83,7 +84,7 @@ impl<'context, 'game> Context<'context, 'game> { .collect() } - pub fn entity_component(&mut self, entity_id: u64) -> &mut T { + pub fn entity_component(&mut self, entity_id: u64) -> &mut T { let entity_type_id = TypeId::of::(); let Entity(_id, components) = self .entities @@ -111,12 +112,19 @@ impl<'context, 'game> Context<'context, 'game> { { let path = path.as_ref().to_path_buf(); let texture: Texture<'game> = unsafe { (*self.texture_creator).load_texture(&path)? }; - self.textures.insert(path.clone(), texture); - Ok(Sprite { path }) + let id = *self.id_counter; + *self.id_counter += 1; + + self.textures.push((id, texture)); + Ok(Sprite(id)) } pub fn draw_sprite(&mut self, sprite: &Sprite, x: i32, y: i32) -> Result<(), Error> { - let texture = &self.textures[&sprite.path]; + let texture = self + .textures + .iter() + .find_map(|v| if v.0 == sprite.0 { Some(&v.1) } else { None }) + .ok_or_else(|| "invalid sprite id")?; self.canvas.copy( texture, None, @@ -136,7 +144,7 @@ impl<'context, 'game> Context<'context, 'game> { self.entities.push(Entity(id, components)); } - pub fn add_system(&mut self, system: Box) { + pub fn add_system(&mut self, system: Rc) { system.on_add(self); self.systems.push(system) } @@ -144,7 +152,9 @@ impl<'context, 'game> Context<'context, 'game> { pub trait System { fn on_add(&self, _ctx: &mut Context) {} - fn on_update(&self, _ctx: &mut Context) {} + fn on_update(&self, _ctx: &mut Context) -> Result<(), Error> { + Ok(()) + } } pub struct Game<'a> { @@ -157,8 +167,8 @@ pub struct Game<'a> { event_pump: sdl2::EventPump, entities: Vec, components: Vec<(u64, Box)>, - systems: Vec>, - textures: HashMap>, + systems: Vec>, + textures: Vec<(Id, Texture<'a>)>, } impl<'game> Game<'game> { @@ -189,11 +199,11 @@ impl<'game> Game<'game> { entities: vec![], components: vec![], systems: vec![], - textures: HashMap::new(), + textures: vec![], }) } - pub fn run(&mut self, f: F) { + pub fn run(&mut self) { 'running: loop { for event in self.event_pump.poll_iter() { match event { @@ -207,11 +217,15 @@ impl<'game> Game<'game> { } self.canvas.set_draw_color(Color::RGB(60, 180, 180)); self.canvas.clear(); - f(&mut self.context()); + for system in self.systems.clone() { + let Err(err) = system.on_update(&mut self.context()) else { + continue; + }; + println!("error occcurred updating system: {err}"); + } self.canvas.present(); std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)) } - self.canvas.present(); } pub fn context<'context>(&'context mut self) -> Context<'context, 'game> diff --git a/src/main.rs b/src/main.rs index 73c98cc..6a8a098 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,32 +1,59 @@ #![allow(dead_code)] use component_macro::Component; -use engine::{Component, Sprite, System}; +use engine::{Sprite, System}; use std::any::{Any, TypeId}; +use std::rc::Rc; mod engine; +use engine::Component; + #[derive(Component)] struct Player { sprite: Option, } +#[derive(Component)] +struct Position(i32, i32); + +struct Gravity; + +impl System for Gravity { + fn on_update(&self, ctx: &mut engine::Context) -> Result<(), engine::Error> { + for id in ctx.entities_with_component::() { + let Position(_, y) = ctx.entity_component::(id); + *y += 1; + } + Ok(()) + } +} + struct PlayerRenderer; impl System for PlayerRenderer { - fn on_add(&self, _ctx: &mut engine::Context) {} - - fn on_update(&self, _ctx: &mut engine::Context) {} + fn on_update(&self, ctx: &mut engine::Context) -> Result<(), engine::Error> { + for id in ctx.entities_with_component::() { + let &mut Position(x, y) = ctx.entity_component::(id); + let player = ctx.entity_component::(id); + let sprite = player.sprite.clone().unwrap(); + ctx.draw_sprite(&sprite, x, y)?; + } + Ok(()) + } } fn main() { let mut game = engine::Game::new().unwrap(); let mut context = game.context(); - context.add_system(Box::new(PlayerRenderer)); - context.spawn(vec![Box::new(Player { sprite: None })]); - - game.run(|context| { - let sprite = context.load_sprite("textures/player.png").unwrap(); - context.draw_sprite(&sprite, 16, 16).unwrap(); - }); + context.add_system(Rc::new(PlayerRenderer)); + context.add_system(Rc::new(Gravity)); + let sprite = context.load_sprite("textures/player.png").unwrap(); + context.spawn(vec![ + Box::new(Player { + sprite: Some(sprite), + }), + Box::new(Position(16, 0)), + ]); + game.run(); }