less cringe sprite drawing
This commit is contained in:
parent
3a3f2a89f6
commit
0dc18414f1
@ -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>
|
||||||
|
47
src/main.rs
47
src/main.rs
@ -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));
|
||||||
|
|
||||||
game.run(|context| {
|
|
||||||
let sprite = context.load_sprite("textures/player.png").unwrap();
|
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();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user