less cringe sprite drawing

This commit is contained in:
Theis Pieter Hollebeek 2024-04-08 13:44:57 +02:00
parent 3a3f2a89f6
commit 0dc18414f1
2 changed files with 74 additions and 33 deletions

View File

@ -1,5 +1,5 @@
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use std::collections::HashMap; use std::rc::Rc;
use std::time::Duration; use std::time::Duration;
use sdl2::{ 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<Box<dyn Component>>); pub type Id = u64;
pub struct Entity(Id, Vec<Box<dyn Component>>);
pub trait Component { pub trait Component {
fn inner_type_id(&self) -> TypeId; fn inner_type_id(&self) -> TypeId;
fn as_any(&mut self) -> &mut dyn Any; fn as_any(&mut self) -> &mut dyn Any;
} }
pub struct Sprite { #[derive(Clone, Copy)]
path: std::path::PathBuf, pub struct Sprite(Id);
}
pub struct Context<'context, 'game> pub struct Context<'context, 'game>
where where
'game: 'context, 'game: 'context,
{ {
id_counter: &'context mut u64, id_counter: &'context mut Id,
canvas: &'context mut Canvas<Window>, canvas: &'context mut Canvas<Window>,
texture_creator: *const TextureCreator<WindowContext>, texture_creator: *const TextureCreator<WindowContext>,
entities: &'context mut Vec<Entity>, entities: &'context mut Vec<Entity>,
systems: &'context mut Vec<Box<dyn System>>, systems: &'context mut Vec<Rc<dyn System>>,
textures: &'context mut HashMap<std::path::PathBuf, Texture<'game>>, textures: &'context mut Vec<(Id, Texture<'game>)>,
} }
impl<'context, 'game> Context<'context, 'game> { impl<'context, 'game> Context<'context, 'game> {
pub fn entities_with_component<T: 'static>(&self) -> Vec<u64> { pub fn entities_with_component<T: 'static + Component>(&self) -> Vec<u64> {
let entity_type_id = TypeId::of::<T>(); let entity_type_id = TypeId::of::<T>();
self.entities self.entities
.iter() .iter()
@ -83,7 +84,7 @@ impl<'context, 'game> Context<'context, 'game> {
.collect() .collect()
} }
pub fn entity_component<T: 'static>(&mut self, entity_id: u64) -> &mut T { pub fn entity_component<T: 'static + Component>(&mut self, entity_id: u64) -> &mut T {
let entity_type_id = TypeId::of::<T>(); let entity_type_id = TypeId::of::<T>();
let Entity(_id, components) = self let Entity(_id, components) = self
.entities .entities
@ -111,12 +112,19 @@ impl<'context, 'game> Context<'context, 'game> {
{ {
let path = path.as_ref().to_path_buf(); let path = path.as_ref().to_path_buf();
let texture: Texture<'game> = unsafe { (*self.texture_creator).load_texture(&path)? }; let texture: Texture<'game> = unsafe { (*self.texture_creator).load_texture(&path)? };
self.textures.insert(path.clone(), texture); let id = *self.id_counter;
Ok(Sprite { path }) *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> { 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( self.canvas.copy(
texture, texture,
None, None,
@ -136,7 +144,7 @@ impl<'context, 'game> Context<'context, 'game> {
self.entities.push(Entity(id, components)); self.entities.push(Entity(id, components));
} }
pub fn add_system(&mut self, system: Box<dyn System>) { pub fn add_system(&mut self, system: Rc<dyn System>) {
system.on_add(self); system.on_add(self);
self.systems.push(system) self.systems.push(system)
} }
@ -144,7 +152,9 @@ impl<'context, 'game> Context<'context, 'game> {
pub trait System { pub trait System {
fn on_add(&self, _ctx: &mut Context) {} 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> { pub struct Game<'a> {
@ -157,8 +167,8 @@ pub struct Game<'a> {
event_pump: sdl2::EventPump, event_pump: sdl2::EventPump,
entities: Vec<Entity>, entities: Vec<Entity>,
components: Vec<(u64, Box<dyn Component>)>, components: Vec<(u64, Box<dyn Component>)>,
systems: Vec<Box<dyn System>>, systems: Vec<Rc<dyn System>>,
textures: HashMap<std::path::PathBuf, Texture<'a>>, textures: Vec<(Id, Texture<'a>)>,
} }
impl<'game> Game<'game> { impl<'game> Game<'game> {
@ -189,11 +199,11 @@ impl<'game> Game<'game> {
entities: vec![], entities: vec![],
components: vec![], components: vec![],
systems: vec![], systems: vec![],
textures: HashMap::new(), textures: vec![],
}) })
} }
pub fn run<F: Fn(&mut Context)>(&mut self, f: F) { pub fn run(&mut self) {
'running: loop { 'running: loop {
for event in self.event_pump.poll_iter() { for event in self.event_pump.poll_iter() {
match event { match event {
@ -207,11 +217,15 @@ impl<'game> Game<'game> {
} }
self.canvas.set_draw_color(Color::RGB(60, 180, 180)); self.canvas.set_draw_color(Color::RGB(60, 180, 180));
self.canvas.clear(); 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(); self.canvas.present();
std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)) std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60))
} }
self.canvas.present();
} }
pub fn context<'context>(&'context mut self) -> Context<'context, 'game> pub fn context<'context>(&'context mut self) -> Context<'context, 'game>

View File

@ -1,32 +1,59 @@
#![allow(dead_code)] #![allow(dead_code)]
use component_macro::Component; use component_macro::Component;
use engine::{Component, Sprite, System}; use engine::{Sprite, System};
use std::any::{Any, TypeId}; use std::any::{Any, TypeId};
use std::rc::Rc;
mod engine; mod engine;
use engine::Component;
#[derive(Component)] #[derive(Component)]
struct Player { struct Player {
sprite: Option<Sprite>, sprite: Option<Sprite>,
} }
#[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::<Position>() {
let Position(_, y) = ctx.entity_component::<Position>(id);
*y += 1;
}
Ok(())
}
}
struct PlayerRenderer; struct PlayerRenderer;
impl System for PlayerRenderer { impl System for PlayerRenderer {
fn on_add(&self, _ctx: &mut engine::Context) {} fn on_update(&self, ctx: &mut engine::Context) -> Result<(), engine::Error> {
for id in ctx.entities_with_component::<Player>() {
fn on_update(&self, _ctx: &mut engine::Context) {} let &mut Position(x, y) = ctx.entity_component::<Position>(id);
let player = ctx.entity_component::<Player>(id);
let sprite = player.sprite.clone().unwrap();
ctx.draw_sprite(&sprite, x, y)?;
}
Ok(())
}
} }
fn main() { fn main() {
let mut game = engine::Game::new().unwrap(); let mut game = engine::Game::new().unwrap();
let mut context = game.context(); let mut context = game.context();
context.add_system(Box::new(PlayerRenderer)); context.add_system(Rc::new(PlayerRenderer));
context.spawn(vec![Box::new(Player { sprite: None })]); context.add_system(Rc::new(Gravity));
let sprite = context.load_sprite("textures/player.png").unwrap();
game.run(|context| { context.spawn(vec![
let sprite = context.load_sprite("textures/player.png").unwrap(); Box::new(Player {
context.draw_sprite(&sprite, 16, 16).unwrap(); sprite: Some(sprite),
}); }),
Box::new(Position(16, 0)),
]);
game.run();
} }