Skip to content

Commit

Permalink
feat: use ecs systems & general tidyup (#5)
Browse files Browse the repository at this point in the history
* feat: added ability to load multiple maps

* fix: potential index out of bounds issue

* feat: start using systems
  • Loading branch information
pbellchambers authored Feb 7, 2021
1 parent 2df6899 commit 1383cc4
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 139 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ edition = "2018"
log = "0.4.14"
simplelog = "0.9.0"
console_engine = "1.4.2"
uuid = { version = "0.8.2", features = ["v4"] }
legion = "0.3.1"
9 changes: 1 addition & 8 deletions assets/maps/default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,4 @@
# #
# #
############################################ ####################################################
########################






%
######################## %
64 changes: 40 additions & 24 deletions src/background_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ mod character_map;
pub(crate) mod tiles;

use crate::background_map::tiles::Tile;
use std::collections::HashMap;
use std::path::PathBuf;
use std::{env, fs, process};

pub struct BackgroundMap {
data: Vec<Vec<Tile>>,
}

impl BackgroundMap {
pub fn new(filename: String) -> BackgroundMap {
initialise_map(filename)
}

pub fn data(&self) -> &Vec<Vec<Tile>> {
&self.data
}
Expand All @@ -22,12 +20,48 @@ impl BackgroundMap {
}
}

fn initialise_map(filename: String) -> BackgroundMap {
let unprocessed_map_data = load_map_data_from_file(filename);
pub fn initialise_all_maps() -> HashMap<String, BackgroundMap> {
let mut all_maps = HashMap::new();
let file_location = get_maps_directory_location();
let paths = fs::read_dir(file_location.as_path()).unwrap();
for path in paths {
let unwrapped_path = path.unwrap();
let filename = String::from(unwrapped_path.file_name().to_str().unwrap());
let map = initialise_map(&unwrapped_path.path());
info!("Initialised map: {:?}", &filename);
all_maps.insert(filename, map);
}
info!("Finished initialising all maps.");
all_maps
}

fn get_maps_directory_location() -> PathBuf {
let mut file_location = env::current_exe().unwrap_or_else(|err| {
error!("Problem getting current executable location: {}", err);
process::exit(1);
});
file_location.pop();
file_location.push("assets");
file_location.push("maps");
file_location
}

fn initialise_map(path: &PathBuf) -> BackgroundMap {
let unprocessed_map_data = load_map_data_from_file(path);
let data = process_map_data(&unprocessed_map_data);
BackgroundMap { data }
}

fn load_map_data_from_file(path: &PathBuf) -> String {
fs::read_to_string(path.as_path()).unwrap_or_else(|err| {
error!(
"Problem getting map data from file: {:?}, error: {}",
path, err
);
process::exit(1);
})
}

fn process_map_data(data: &str) -> Vec<Vec<Tile>> {
let mut processed_data: Vec<Vec<Tile>> = Vec::new();
let mut row_data: Vec<Tile> = Vec::new();
Expand Down Expand Up @@ -55,21 +89,3 @@ fn process_map_data(data: &str) -> Vec<Vec<Tile>> {
}
processed_data
}

fn load_map_data_from_file(filename: String) -> String {
let mut file_location = env::current_exe().unwrap_or_else(|err| {
error!("Problem getting current executable location: {}", err);
process::exit(1);
});
file_location.pop();
file_location.push("assets");
file_location.push("maps");
file_location.push(filename);
fs::read_to_string(&file_location.as_path()).unwrap_or_else(|err| {
error!(
"Problem getting map data from file: {:?}, error: {}",
file_location, err
);
process::exit(1);
})
}
2 changes: 1 addition & 1 deletion src/background_map/tiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub enum OpenState {
}

#[derive(Clone, Copy)]
pub struct Location {
pub struct TilePosition {
pub x: i32,
pub y: i32,
}
Expand Down
6 changes: 3 additions & 3 deletions src/background_map/tiles/door.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::background_map::tiles::{Collidable, Location, OpenState};
use crate::background_map::tiles::{Collidable, OpenState, TilePosition};

#[derive(Clone, Copy)]
pub struct Door {
pub location: Location,
pub tile_position: TilePosition,
pub character_icon: char,
pub collidable: Collidable,
pub open_state: OpenState,
Expand All @@ -11,7 +11,7 @@ pub struct Door {
impl Door {
pub fn new(x: i32, y: i32, open_state: OpenState) -> Door {
Door {
location: Location { x, y },
tile_position: TilePosition { x, y },
character_icon: match open_state {
OpenState::Open => '/',
OpenState::Closed => '+',
Expand Down
6 changes: 3 additions & 3 deletions src/background_map/tiles/wall.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use crate::background_map::tiles::{Collidable, Location};
use crate::background_map::tiles::{Collidable, TilePosition};

#[derive(Clone, Copy)]
pub struct Wall {
pub location: Location,
pub tile_position: TilePosition,
pub character_icon: char,
pub collidable: Collidable,
}

impl Wall {
pub fn new(x: i32, y: i32, character_icon: char) -> Wall {
Wall {
location: Location { x, y },
tile_position: TilePosition { x, y },
character_icon,
collidable: Collidable::True,
}
Expand Down
1 change: 1 addition & 0 deletions src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const DEFAULT_MAP: &str = "default.txt";
9 changes: 2 additions & 7 deletions src/ecs/components.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use console_engine::Color;
use uuid::Uuid;

#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct Position {
pub x: i32,
pub y: i32,
pub map: String,
}

#[derive(Clone, Copy, Debug, PartialEq)]
Expand Down Expand Up @@ -42,8 +42,3 @@ pub struct IsPlayer {
pub struct VisibleState {
pub visible: bool,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PlayerId {
pub uuid: Uuid,
}
128 changes: 71 additions & 57 deletions src/engine.rs
Original file line number Diff line number Diff line change
@@ -1,104 +1,118 @@
use crate::background_map;
use crate::background_map::tiles::{Collidable, Tile};
use crate::background_map::BackgroundMap;
use crate::consts::DEFAULT_MAP;
use crate::ecs::components;
use crate::ecs::components::*;
use crate::viewport::Viewport;
use console_engine::{Color, ConsoleEngine, KeyCode, KeyModifiers};
use legion::*;
use uuid::Uuid;
use std::collections::HashMap;

pub fn run(width: u32, height: u32, target_fps: u32) {
let viewport = Viewport::new(width, height, target_fps);
let mut console =
console_engine::ConsoleEngine::init(viewport.width, viewport.height, viewport.target_fps);
let mut world = World::default();
let background_map = BackgroundMap::new(String::from("default.txt"));
info!("Initialised default map.");
let all_maps_resource = background_map::initialise_all_maps();
let all_maps = background_map::initialise_all_maps();
let current_player_entity = create_player(&mut world);

let current_player_uuid = create_player(&mut world);
info!("Initialised player: {}", &current_player_uuid);
let mut schedule = Schedule::builder()
.add_system(update_player_input_system())
.add_system(update_entities_position_system())
.build();

let mut resources = Resources::default();
resources.insert(all_maps_resource);

loop {
console.wait_frame();
console.clear_screen();
world = update_player_input(world, &console, &current_player_uuid);
world = update_entities(world, &background_map);
viewport.draw_viewport_contents(
&mut console,
&world,
&background_map,
&current_player_uuid,
);

resources.insert(get_player_updates(current_player_entity, &console));

schedule.execute(&mut world, &mut resources);

viewport.draw_viewport_contents(&mut console, &world, all_maps.get(DEFAULT_MAP).unwrap());
if should_quit(&console) {
info!("Ctrl-q detected - quitting app.");
break;
}
}
}

fn should_quit(console: &ConsoleEngine) -> bool {
console.is_key_pressed_with_modifier(KeyCode::Char('q'), KeyModifiers::CONTROL)
}

fn create_player(world: &mut World) -> Uuid {
let uuid = Uuid::new_v4();
fn create_player(world: &mut World) -> Entity {
let player = world.push((
IsPlayer { is_player: true },
Position { x: 5, y: 5 },
Position {
x: 5,
y: 5,
map: DEFAULT_MAP.to_string(),
},
components::Velocity { x: 0, y: 0 },
CollisionState { collidable: true },
Character { icon: '@' },
EntityColour {
colour: Color::Magenta,
},
VisibleState { visible: true },
PlayerId { uuid },
));
info!("Created player: {:?}, with uuid: {:?}", player, uuid);
uuid
info!("Created player: {:?}", player);
player
}

fn update_player_input(
mut world: World,
fn get_player_updates(
current_player_entity: Entity,
console: &ConsoleEngine,
current_player_uuid: &Uuid,
) -> World {
let mut query = <(&mut Velocity, &PlayerId)>::query();

for (velocity, player_id) in query.iter_mut(&mut world) {
if player_id.uuid == *current_player_uuid {
if console.is_key_held(KeyCode::Up) {
velocity.y = -1;
} else if console.is_key_held(KeyCode::Down) {
velocity.y = 1;
} else if console.is_key_held(KeyCode::Left) {
velocity.x = -1;
} else if console.is_key_held(KeyCode::Right) {
velocity.x = 1;
}
break;
} else {
// do nothing
}
) -> HashMap<Entity, Velocity> {
let mut updates = HashMap::new();
if console.is_key_held(KeyCode::Up) {
updates.insert(current_player_entity, Velocity { x: 0, y: -1 });
} else if console.is_key_held(KeyCode::Down) {
updates.insert(current_player_entity, Velocity { x: 0, y: 1 });
} else if console.is_key_held(KeyCode::Left) {
updates.insert(current_player_entity, Velocity { x: -1, y: 0 });
} else if console.is_key_held(KeyCode::Right) {
updates.insert(current_player_entity, Velocity { x: 1, y: 0 });
}
world
updates
}

fn update_entities(mut world: World, background_map: &BackgroundMap) -> World {
let mut query = <(&mut Velocity, &mut Position)>::query();
fn should_quit(console: &ConsoleEngine) -> bool {
console.is_key_pressed_with_modifier(KeyCode::Char('q'), KeyModifiers::CONTROL)
}

for (velocity, position) in query.iter_mut(&mut world) {
if !entity_is_colliding(background_map.get_tile_at(
(position.x + velocity.x) as usize,
(position.y + velocity.y) as usize,
)) {
position.x += velocity.x;
position.y += velocity.y;
#[system(par_for_each)]
fn update_player_input(
entity: &Entity,
velocity: &mut Velocity,
#[resource] player_updates: &HashMap<Entity, Velocity>,
) {
for (update_entity, update_velocity) in player_updates {
if update_entity == entity {
velocity.x = update_velocity.x;
velocity.y = update_velocity.y;
}
velocity.x = 0;
velocity.y = 0;
}
world
}

#[system(par_for_each)]
fn update_entities_position(
velocity: &mut Velocity,
position: &mut Position,
#[resource] all_maps: &HashMap<String, BackgroundMap>,
) {
let current_map = all_maps.get(&position.map).unwrap();
if !entity_is_colliding(current_map.get_tile_at(
(position.x + velocity.x) as usize,
(position.y + velocity.y) as usize,
)) {
position.x += velocity.x;
position.y += velocity.y;
}
velocity.x = 0;
velocity.y = 0;
}

fn entity_is_colliding(tile: Tile) -> bool {
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod background_map;
mod consts;
mod ecs;
mod engine;
mod viewport;
Expand Down
Loading

0 comments on commit 1383cc4

Please sign in to comment.