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::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<Box<dyn Component>>);
pub type Id = u64;
pub struct Entity(Id, Vec<Box<dyn Component>>);
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<Window>,
texture_creator: *const TextureCreator<WindowContext>,
entities: &'context mut Vec<Entity>,
systems: &'context mut Vec<Box<dyn System>>,
textures: &'context mut HashMap<std::path::PathBuf, Texture<'game>>,
systems: &'context mut Vec<Rc<dyn System>>,
textures: &'context mut Vec<(Id, Texture<'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>();
self.entities
.iter()
@ -83,7 +84,7 @@ impl<'context, 'game> Context<'context, 'game> {
.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(_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<dyn System>) {
pub fn add_system(&mut self, system: Rc<dyn System>) {
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<Entity>,
components: Vec<(u64, Box<dyn Component>)>,
systems: Vec<Box<dyn System>>,
textures: HashMap<std::path::PathBuf, Texture<'a>>,
systems: Vec<Rc<dyn System>>,
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<F: Fn(&mut Context)>(&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>

View File

@ -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<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;
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::<Player>() {
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() {
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| {
context.add_system(Rc::new(PlayerRenderer));
context.add_system(Rc::new(Gravity));
let sprite = context.load_sprite("textures/player.png").unwrap();
context.draw_sprite(&sprite, 16, 16).unwrap();
});
context.spawn(vec![
Box::new(Player {
sprite: Some(sprite),
}),
Box::new(Position(16, 0)),
]);
game.run();
}