Migrate to Legion for ECS
This commit is contained in:
		
							
								
								
									
										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); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user