forked from tutorials/rust-sokoban
Finish 2.3, Pushing boxes
This commit is contained in:
parent
8c37bacafb
commit
403be94983
@ -1,11 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rust-sokoban"
|
name = "rust-sokoban"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Timothy Warren <twarren@nabancard.com>"]
|
authors = ["Timothy Warren <tim@timshomepage.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ggez = "0.5.1"
|
ggez = "0.5.1"
|
||||||
specs = { version="0.15.0", features=["specs-derive"] }
|
specs = { version="0.16.1", features=["specs-derive"] }
|
91
src/main.rs
91
src/main.rs
@ -5,14 +5,19 @@ use ggez::graphics::DrawParam;
|
|||||||
use ggez::graphics::Image;
|
use ggez::graphics::Image;
|
||||||
use ggez::nalgebra as na;
|
use ggez::nalgebra as na;
|
||||||
use ggez::{conf, event, Context, GameResult};
|
use ggez::{conf, event, Context, GameResult};
|
||||||
|
use specs::world::Index;
|
||||||
|
use specs::Entities;
|
||||||
|
use specs::NullStorage;
|
||||||
|
use specs::WriteStorage;
|
||||||
use specs::{
|
use specs::{
|
||||||
join::Join, Builder, Component, Read, ReadStorage, RunNow, System, VecStorage, World, WorldExt,
|
join::Join, Builder, Component, ReadStorage, RunNow, System, VecStorage, World, WorldExt, Write,
|
||||||
Write, WriteStorage,
|
|
||||||
};
|
};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path;
|
use std::path;
|
||||||
|
|
||||||
const TILE_WIDTH: f32 = 32.0;
|
const TILE_WIDTH: f32 = 32.0;
|
||||||
|
const MAP_WIDTH: u8 = 8;
|
||||||
|
const MAP_HEIGHT: u8 = 9;
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
#[derive(Debug, Component, Clone, Copy)]
|
#[derive(Debug, Component, Clone, Copy)]
|
||||||
@ -51,6 +56,14 @@ pub struct Box {}
|
|||||||
#[storage(VecStorage)]
|
#[storage(VecStorage)]
|
||||||
pub struct BoxSpot {}
|
pub struct BoxSpot {}
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[storage(NullStorage)]
|
||||||
|
pub struct Movable;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[storage(NullStorage)]
|
||||||
|
pub struct Immovable;
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct InputQueue {
|
pub struct InputQueue {
|
||||||
@ -101,17 +114,77 @@ impl<'a> System<'a> for InputSystem {
|
|||||||
// Data
|
// Data
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
Write<'a, InputQueue>,
|
Write<'a, InputQueue>,
|
||||||
|
Entities<'a>,
|
||||||
WriteStorage<'a, Position>,
|
WriteStorage<'a, Position>,
|
||||||
ReadStorage<'a, Player>,
|
ReadStorage<'a, Player>,
|
||||||
|
ReadStorage<'a, Movable>,
|
||||||
|
ReadStorage<'a, Immovable>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
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
|
// Get the first key pressed
|
||||||
if let Some(key) = input_queue.keys_pressed.pop() {
|
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 {
|
match key {
|
||||||
KeyCode::Up => position.y -= 1,
|
KeyCode::Up => position.y -= 1,
|
||||||
KeyCode::Down => position.y += 1,
|
KeyCode::Down => position.y += 1,
|
||||||
@ -171,6 +244,8 @@ pub fn register_components(world: &mut World) {
|
|||||||
world.register::<Wall>();
|
world.register::<Wall>();
|
||||||
world.register::<Box>();
|
world.register::<Box>();
|
||||||
world.register::<BoxSpot>();
|
world.register::<BoxSpot>();
|
||||||
|
world.register::<Movable>();
|
||||||
|
world.register::<Immovable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_resources(world: &mut World) {
|
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(),
|
path: "/images/wall.png".to_string(),
|
||||||
})
|
})
|
||||||
.with(Wall {})
|
.with(Wall {})
|
||||||
|
.with(Immovable)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +281,8 @@ pub fn create_box(world: &mut World, position: Position) {
|
|||||||
.with(Renderable {
|
.with(Renderable {
|
||||||
path: "/images/box.png".to_string(),
|
path: "/images/box.png".to_string(),
|
||||||
})
|
})
|
||||||
|
.with(Box {})
|
||||||
|
.with(Movable)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +305,7 @@ pub fn create_player(world: &mut World, position: Position) {
|
|||||||
path: "/images/player.png".to_string(),
|
path: "/images/player.png".to_string(),
|
||||||
})
|
})
|
||||||
.with(Player {})
|
.with(Player {})
|
||||||
|
.with(Movable)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user