diff --git a/Cargo.toml b/Cargo.toml index 3a4b628..9fb6709 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "rust-sokoban" version = "0.1.0" -authors = ["Timothy Warren "] +authors = ["Timothy Warren "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] ggez = "0.5.1" -specs = { version="0.15.0", features=["specs-derive"] } \ No newline at end of file +specs = { version="0.16.1", features=["specs-derive"] } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d09eece..dd2ea19 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,14 +5,19 @@ use ggez::graphics::DrawParam; use ggez::graphics::Image; use ggez::nalgebra as na; use ggez::{conf, event, Context, GameResult}; +use specs::world::Index; +use specs::Entities; +use specs::NullStorage; +use specs::WriteStorage; use specs::{ - join::Join, Builder, Component, Read, ReadStorage, RunNow, System, VecStorage, World, WorldExt, - Write, WriteStorage, + join::Join, Builder, Component, ReadStorage, RunNow, System, VecStorage, World, WorldExt, Write, }; - +use std::collections::HashMap; use std::path; const TILE_WIDTH: f32 = 32.0; +const MAP_WIDTH: u8 = 8; +const MAP_HEIGHT: u8 = 9; // Components #[derive(Debug, Component, Clone, Copy)] @@ -51,6 +56,14 @@ pub struct Box {} #[storage(VecStorage)] pub struct BoxSpot {} +#[derive(Component, Default)] +#[storage(NullStorage)] +pub struct Movable; + +#[derive(Component, Default)] +#[storage(NullStorage)] +pub struct Immovable; + // Resources #[derive(Default)] pub struct InputQueue { @@ -101,17 +114,77 @@ impl<'a> System<'a> for InputSystem { // Data type SystemData = ( Write<'a, InputQueue>, + Entities<'a>, WriteStorage<'a, Position>, ReadStorage<'a, Player>, + ReadStorage<'a, Movable>, + ReadStorage<'a, Immovable>, ); fn run(&mut self, data: Self::SystemData) { - let (mut input_queue, mut positions, players) = data; + let (mut input_queue, entities, mut positions, players, movables, immovables) = data; - for (position, _player) in (&mut positions, &players).join() { + let mut to_move = Vec::new(); + + for (position, _player) in (&positions, &players).join() { // Get the first key pressed if let Some(key) = input_queue.keys_pressed.pop() { - // Apply the key to the position + // get all the movables and immovables + let mov: HashMap<(u8, u8), Index> = (&entities, &movables, &positions) + .join() + .map(|t| ((t.2.x, t.2.y), t.0.id())) + .collect(); + let immov: HashMap<(u8, u8), Index> = (&entities, &immovables, &positions) + .join() + .map(|t| ((t.2.x, t.2.y), t.0.id())) + .collect(); + + // Now iterate through current position to the end of the map + // on the correct axis and check what needs to move. + let (start, end, is_x) = match key { + KeyCode::Up => (position.y, 0, false), + KeyCode::Down => (position.y, MAP_HEIGHT, false), + KeyCode::Left => (position.x, 0, true), + KeyCode::Right => (position.x, MAP_WIDTH, true), + _ => continue, + }; + + let range: Vec<_> = if start < end { + (start..=end).collect() + } else { + (end..=start).rev().collect() + }; + + for x_or_y in range { + let pos = if is_x { + (x_or_y, position.y) + } else { + (position.x, x_or_y) + }; + + // find a movable + // if it exists, we try to move it and continue + // if it doesn't exist, we continue and try to find an immovable instead + match mov.get(&pos) { + Some(id) => to_move.push((key, id.clone())), + None => { + // find an immovable + // if it exists, we need to stop and not move anything + // if it doesn't exist, we stop because we found a gap + match immov.get(&pos) { + Some(_) => to_move.clear(), + None => break, + } + } + } + } + } + } + + // Now actually move what needs to be moved + for (key, id) in to_move { + let position = positions.get_mut(entities.entity(id)); + if let Some(position) = position { match key { KeyCode::Up => position.y -= 1, KeyCode::Down => position.y += 1, @@ -171,6 +244,8 @@ pub fn register_components(world: &mut World) { world.register::(); world.register::(); world.register::(); + world.register::(); + world.register::(); } pub fn register_resources(world: &mut World) { @@ -185,6 +260,7 @@ pub fn create_wall(world: &mut World, position: Position) { path: "/images/wall.png".to_string(), }) .with(Wall {}) + .with(Immovable) .build(); } @@ -205,6 +281,8 @@ pub fn create_box(world: &mut World, position: Position) { .with(Renderable { path: "/images/box.png".to_string(), }) + .with(Box {}) + .with(Movable) .build(); } @@ -227,6 +305,7 @@ pub fn create_player(world: &mut World, position: Position) { path: "/images/player.png".to_string(), }) .with(Player {}) + .with(Movable) .build(); }