add ecs architecture

This commit is contained in:
unintendedfraud
2024-02-03 02:26:30 +01:00
parent c4e1455148
commit 689a8d4176
10 changed files with 149 additions and 90 deletions
+1
View File
@@ -7,3 +7,4 @@ edition = "2021"
[dependencies] [dependencies]
bracket-lib = "~0.8.1" bracket-lib = "~0.8.1"
legion = "=0.3.1"
+10
View File
@@ -0,0 +1,10 @@
pub use crate::prelude::*;
#[derive(Clone, Debug, Copy, PartialEq)]
pub struct Render {
pub color: ColorPair,
pub glyph: FontCharType,
}
#[derive(Clone, Debug, Copy, PartialEq)]
pub struct Player;
+27 -12
View File
@@ -1,14 +1,22 @@
mod map; mod map;
mod player;
mod map_builder; mod map_builder;
mod camera; mod camera;
mod components;
mod spawner;
mod systems;
mod prelude { mod prelude {
pub use bracket_lib::prelude::*; pub use bracket_lib::prelude::*;
pub use legion::*;
pub use legion::world::SubWorld;
pub use legion::systems::CommandBuffer;
pub use crate::map::*; pub use crate::map::*;
pub use crate::player::*;
pub use crate::map_builder::*; pub use crate::map_builder::*;
pub use crate::camera::*; pub use crate::camera::*;
pub use crate::components::*;
pub use crate::spawner::*;
pub use crate::systems::*;
pub const SCREEN_WIDTH: i32 = 80; pub const SCREEN_WIDTH: i32 = 80;
pub const SCREEN_HEIGHT: i32 = 50; pub const SCREEN_HEIGHT: i32 = 50;
@@ -22,20 +30,27 @@ const FONT_PATH: &str = "dungeonfont.png";
use prelude::*; use prelude::*;
struct State { struct State {
map: Map, ecs: World,
player: Player, resources: Resources,
camera: Camera, systems: Schedule,
} }
impl State { impl State {
fn new() -> Self { fn new() -> Self {
let mut ecs = World::default();
let mut resources = Resources::default();
let mut rng = RandomNumberGenerator::new(); let mut rng = RandomNumberGenerator::new();
let mb = MapBuilder::new(&mut rng); let map_builder = MapBuilder::new(&mut rng);
resources.insert(map_builder.map);
resources.insert(Camera::new(map_builder.player_start));
spawn_player(&mut ecs, map_builder.player_start);
return Self { return Self {
map: mb.map, ecs,
player: Player::new(mb.player_start), resources,
camera: Camera::new(mb.player_start), systems: build_scheduler(),
}; };
} }
} }
@@ -47,9 +62,9 @@ impl GameState for State {
ctx.set_active_console(1); ctx.set_active_console(1);
ctx.cls(); ctx.cls();
self.player.update(ctx, &self.map, &mut self.camera); self.resources.insert(ctx.key);
self.map.render(ctx, &self.camera); self.systems.execute(&mut self.ecs, &mut self.resources);
self.player.render(ctx, &self.camera); render_draw_buffer(ctx).expect("failed to draw buffer");
} }
} }
-33
View File
@@ -38,37 +38,4 @@ impl Map {
return None; return None;
} }
} }
pub fn render(&self, ctx: &mut BTerm, camera: &Camera) {
ctx.set_active_console(0);
for y in camera.top_y..camera.bottom_y {
for x in camera.left_x..camera.right_x {
if self.in_bounds(Point::new(x, y)) {
let idx = map_idx(x, y);
match self.tiles[idx] {
TileType::Wall => {
ctx.set(
x - camera.left_x,
y - camera.top_y,
WHITE,
BLACK,
to_cp437('#'),
);
}
TileType::Floor => {
ctx.set(
x - camera.left_x,
y - camera.top_y,
WHITE,
BLACK,
to_cp437('.'),
);
}
}
}
}
}
}
} }
-45
View File
@@ -1,45 +0,0 @@
use crate::prelude::*;
pub struct Player {
pub hp: i32,
pub position: Point,
}
impl Player {
pub fn new(point: Point) -> Self {
return Self {
hp: 100,
position: point,
};
}
pub fn update(&mut self, ctx: &mut BTerm, map: &Map, camera: &mut Camera) {
if let Some(key) = ctx.key {
let delta = match key {
VirtualKeyCode::Up => Point::new(0, -1),
VirtualKeyCode::Right => Point::new(1, 0),
VirtualKeyCode::Down => Point::new(0, 1),
VirtualKeyCode::Left => Point::new(-1, 0),
_ => Point::zero(),
};
let new_pos = self.position + delta;
if map.can_enter_tile(new_pos) {
self.position = new_pos;
camera.on_player_move(new_pos);
}
}
}
pub fn render(&self, ctx: &mut BTerm, camera: &Camera) {
ctx.set_active_console(1);
return ctx.set(
self.position.x - camera.left_x,
self.position.y - camera.top_y,
WHITE,
BLACK,
to_cp437('@')
);
}
}
+12
View File
@@ -0,0 +1,12 @@
pub use crate::prelude::*;
pub fn spawn_player(ecs: &mut World, pos: Point) {
ecs.push((
Player,
pos,
Render{
color: ColorPair::new(WHITE, BLACK),
glyph: to_cp437('@'),
},
));
}
@@ -0,0 +1,26 @@
use crate::prelude::*;
#[system]
#[read_component(Point)]
#[read_component(Render)]
pub fn entity_render(
ecs: &SubWorld,
#[resource] camera: &Camera,
) {
let mut draw_batch = DrawBatch::new();
draw_batch.target(1);
let offset = Point::new(camera.left_x, camera.top_y);
<(&Point, &Render)>::query()
.iter(ecs)
.for_each(|(pos, render)| {
draw_batch.set(
*pos - offset,
render.color,
render.glyph,
);
});
draw_batch.submit(5000).expect("failed to draw batch");
}
+28
View File
@@ -0,0 +1,28 @@
use crate::prelude::*;
#[system]
pub fn map_render(
#[resource] map: &Map,
#[resource] camera: &Camera,
) {
let mut draw_batch = DrawBatch::new();
draw_batch.target(0);
for y in camera.top_y ..= camera.bottom_y {
for x in camera.left_x .. camera.right_x {
let p = Point::new(x, y);
let offset = Point::new(camera.left_x, camera.top_y);
if map.in_bounds(p) {
let idx = map_idx(x, y);
let glyph = match map.tiles[idx] {
TileType::Wall => to_cp437('#'),
TileType::Floor => to_cp437('.'),
};
draw_batch.set(p - offset, ColorPair::new(WHITE, BLACK), glyph);
}
}
}
draw_batch.submit(0).expect("failed to draw batch");
}
+13
View File
@@ -0,0 +1,13 @@
mod player_input;
mod map_render;
mod entity_render;
pub use crate::prelude::*;
pub fn build_scheduler() -> Schedule {
return Schedule::builder()
.add_system(player_input::player_input_system())
.add_system(map_render::map_render_system())
.add_system(entity_render::entity_render_system())
.build();
}
@@ -0,0 +1,32 @@
use crate::prelude::*;
#[system]
#[write_component(Point)]
#[read_component(Player)]
pub fn player_input(
ecs: &mut SubWorld,
#[resource] map: &Map,
#[resource] key: &Option<VirtualKeyCode>,
#[resource] camera: &mut Camera,
) {
if let Some(key) = key {
let delta = match key {
VirtualKeyCode::Up => Point::new(0, -1),
VirtualKeyCode::Right => Point::new(1, 0),
VirtualKeyCode::Down => Point::new(0, 1),
VirtualKeyCode::Left => Point::new(-1, 0),
_ => Point::new(0, 0),
};
if delta.x != 0 || delta.y != 0 {
let mut players = <&mut Point>::query().filter(component::<Player>());
players.iter_mut(ecs).for_each(|pos| {
let destination = *pos + delta;
if map.can_enter_tile(destination) {
*pos = destination;
camera.on_player_move(destination);
}
});
}
}
}