Migrate to Legion for ECS
This commit is contained in:
parent
752414d8b5
commit
dcfc284f45
10
src/components.rs
Normal file
10
src/components.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Render {
|
||||||
|
pub color: ColorPair,
|
||||||
|
pub glyph: FontCharType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Player;
|
36
src/main.rs
36
src/main.rs
@ -1,37 +1,51 @@
|
|||||||
mod camera;
|
mod camera;
|
||||||
|
mod components;
|
||||||
mod map;
|
mod map;
|
||||||
mod map_builder;
|
mod map_builder;
|
||||||
mod player;
|
mod spawner;
|
||||||
|
mod systems;
|
||||||
|
|
||||||
mod prelude {
|
mod prelude {
|
||||||
pub use bracket_lib::prelude::*;
|
pub use bracket_lib::prelude::*;
|
||||||
|
pub use legion::systems::CommandBuffer;
|
||||||
|
pub use legion::world::SubWorld;
|
||||||
|
pub use legion::*;
|
||||||
pub const SCREEN_WIDTH: i32 = 80;
|
pub const SCREEN_WIDTH: i32 = 80;
|
||||||
pub const SCREEN_HEIGHT: i32 = 50;
|
pub const SCREEN_HEIGHT: i32 = 50;
|
||||||
pub const DISPLAY_WIDTH: i32 = SCREEN_WIDTH / 2;
|
pub const DISPLAY_WIDTH: i32 = SCREEN_WIDTH / 2;
|
||||||
pub const DISPLAY_HEIGHT: i32 = SCREEN_HEIGHT / 2;
|
pub const DISPLAY_HEIGHT: i32 = SCREEN_HEIGHT / 2;
|
||||||
pub use crate::camera::*;
|
pub use crate::camera::*;
|
||||||
|
pub use crate::components::*;
|
||||||
pub use crate::map::*;
|
pub use crate::map::*;
|
||||||
pub use crate::map_builder::*;
|
pub use crate::map_builder::*;
|
||||||
pub use crate::player::*;
|
pub use crate::spawner::*;
|
||||||
|
pub use crate::systems::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 map_builder = 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);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
map: map_builder.map,
|
ecs,
|
||||||
player: Player::new(map_builder.player_start),
|
resources,
|
||||||
camera: Camera::new(map_builder.player_start),
|
systems: build_scheduler(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,9 +56,9 @@ impl GameState for State {
|
|||||||
ctx.cls();
|
ctx.cls();
|
||||||
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("Render error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
31
src/map.rs
31
src/map.rs
@ -23,37 +23,6 @@ impl Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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::Floor => {
|
|
||||||
ctx.set(
|
|
||||||
x - camera.left_x,
|
|
||||||
y - camera.top_y,
|
|
||||||
WHITE,
|
|
||||||
BLACK,
|
|
||||||
to_cp437('.'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
TileType::Wall => {
|
|
||||||
ctx.set(
|
|
||||||
x - camera.left_x,
|
|
||||||
y - camera.top_y,
|
|
||||||
WHITE,
|
|
||||||
BLACK,
|
|
||||||
to_cp437('#'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn in_bounds(&self, point: Point) -> bool {
|
pub fn in_bounds(&self, point: Point) -> bool {
|
||||||
point.x >= 0 && point.x < SCREEN_WIDTH && point.y >= 0 && point.y < SCREEN_HEIGHT
|
point.x >= 0 && point.x < SCREEN_WIDTH && point.y >= 0 && point.y < SCREEN_HEIGHT
|
||||||
}
|
}
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
pub struct Player {
|
|
||||||
pub position: Point,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Player {
|
|
||||||
pub fn new(position: Point) -> Self {
|
|
||||||
Self { position }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(&self, ctx: &mut BTerm, camera: &Camera) {
|
|
||||||
ctx.set_active_console(1);
|
|
||||||
ctx.set(
|
|
||||||
self.position.x - camera.left_x,
|
|
||||||
self.position.y - camera.top_y,
|
|
||||||
WHITE,
|
|
||||||
BLACK,
|
|
||||||
to_cp437('@'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(&mut self, ctx: &mut BTerm, map: &Map, camera: &mut Camera) {
|
|
||||||
if let Some(key) = ctx.key {
|
|
||||||
let delta = match key {
|
|
||||||
VirtualKeyCode::Left | VirtualKeyCode::A => Point::new(-1, 0),
|
|
||||||
VirtualKeyCode::Right | VirtualKeyCode::D => Point::new(1, 0),
|
|
||||||
VirtualKeyCode::Up | VirtualKeyCode::W => Point::new(0, -1),
|
|
||||||
VirtualKeyCode::Down | VirtualKeyCode::S => Point::new(0, 1),
|
|
||||||
_ => Point::zero(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_position = self.position + delta;
|
|
||||||
if map.can_enter_tile(new_position) {
|
|
||||||
self.position = new_position;
|
|
||||||
camera.on_player_move(new_position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
12
src/spawner.rs
Normal file
12
src/spawner.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
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('@'),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
17
src/systems/entity_render.rs
Normal file
17
src/systems/entity_render.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
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();
|
||||||
|
let offset = Point::new(camera.left_x, camera.top_y);
|
||||||
|
|
||||||
|
draw_batch.target(1);
|
||||||
|
<(&Point, &Render)>::query()
|
||||||
|
.iter(ecs)
|
||||||
|
.for_each(|(pos, render)| {
|
||||||
|
draw_batch.set(*pos - offset, render.color, render.glyph);
|
||||||
|
});
|
||||||
|
draw_batch.submit(5000).expect("Batch error");
|
||||||
|
}
|
22
src/systems/map_render.rs
Normal file
22
src/systems/map_render.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
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 pt = Point::new(x, y);
|
||||||
|
let offset = Point::new(camera.left_x, camera.top_y);
|
||||||
|
if map.in_bounds(pt) {
|
||||||
|
let idx = map_idx(x, y);
|
||||||
|
let glyph = match map.tiles[idx] {
|
||||||
|
TileType::Floor => to_cp437('.'),
|
||||||
|
TileType::Wall => to_cp437('#'),
|
||||||
|
};
|
||||||
|
draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_batch.submit(0).expect("Batch error");
|
||||||
|
}
|
13
src/systems/mod.rs
Normal file
13
src/systems/mod.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
mod entity_render;
|
||||||
|
mod map_render;
|
||||||
|
mod player_input;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn build_scheduler() -> Schedule {
|
||||||
|
Schedule::builder()
|
||||||
|
.add_system(player_input::player_input_system())
|
||||||
|
.add_system(map_render::map_render_system())
|
||||||
|
.add_system(entity_render::entity_render_system())
|
||||||
|
.build()
|
||||||
|
}
|
34
src/systems/player_input.rs
Normal file
34
src/systems/player_input.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
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::Left | VirtualKeyCode::A => Point::new(-1, 0),
|
||||||
|
VirtualKeyCode::Right | VirtualKeyCode::D => Point::new(1, 0),
|
||||||
|
VirtualKeyCode::Up | VirtualKeyCode::W => Point::new(0, -1),
|
||||||
|
VirtualKeyCode::Down | VirtualKeyCode::S => Point::new(0, 1),
|
||||||
|
_ => Point::zero(),
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user