Compare commits
No commits in common. "master" and "master" have entirely different histories.
BIN
resources/images/_/box.png
Normal file
After Width: | Height: | Size: 582 B |
BIN
resources/images/_/box_spot.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
resources/images/_/floor.png
Normal file
After Width: | Height: | Size: 397 B |
BIN
resources/images/_/player.png
Normal file
After Width: | Height: | Size: 669 B |
BIN
resources/images/_/wall.png
Normal file
After Width: | Height: | Size: 598 B |
Before Width: | Height: | Size: 742 B |
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 234 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB |
BIN
resources/images/box_red.png
Executable file → Normal file
Before Width: | Height: | Size: 761 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 234 B |
BIN
resources/images/box_spot_blue.png
Executable file → Normal file
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 172 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
BIN
resources/images/box_spot_red.png
Executable file → Normal file
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 172 B |
BIN
resources/images/floor.png
Executable file → Normal file
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 172 B |
Before Width: | Height: | Size: 172 B |
Before Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 264 B |
Before Width: | Height: | Size: 299 B |
Before Width: | Height: | Size: 298 B |
Before Width: | Height: | Size: 167 B |
BIN
resources/images/player_1.png
Executable file → Normal file
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 264 B |
BIN
resources/images/player_2.png
Executable file → Normal file
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 299 B |
BIN
resources/images/player_3.png
Executable file → Normal file
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 298 B |
BIN
resources/images/wall.png
Executable file → Normal file
Before Width: | Height: | Size: 740 B After Width: | Height: | Size: 167 B |
1411
resources/maps.txt
@ -1,11 +0,0 @@
|
||||
- - - - X X X X X - - - - - - - - - - - - -
|
||||
- - - - X . . . X - - - - - - - - - - - - -
|
||||
- - - - X * . . X - - - - - - - - - - - - -
|
||||
- - X X X . . * X X X - - - - - - - - - - -
|
||||
- - X . . * . . * . X - - - - - - - - - - -
|
||||
X X X . X . X X X . X - - - - - X X X X X X
|
||||
X . . . X . X X X . X X X X X X X . . % % X
|
||||
X . * . . * . . . . . . . . . . . . . % % X
|
||||
X X X X X . X X X X . X @ X X X X . . % % X
|
||||
- - - - X . . . . . . X X X - - X X X X X X
|
||||
- - - - X X X X X X X X - - - - - - - - - -
|
@ -1,10 +0,0 @@
|
||||
X X X X X X X X X X X X - -
|
||||
X % % . . X . . . . . X X X
|
||||
X % % . . X . * . . * . . X
|
||||
X % % . . X * X X X X . . X
|
||||
X % % . . . . @ . X X . . X
|
||||
X % % . . X . X . . * . X X
|
||||
X X X X X X . X X * . * . X
|
||||
- - X . * . . * . * . * . X
|
||||
- - X . . . . X . . . . . X
|
||||
- - X X X X X X X X X X X X
|
@ -1,10 +0,0 @@
|
||||
- - - - - - - - X X X X X X X X -
|
||||
- - - - - - - - X . . . . . @ X -
|
||||
- - - - - - - - X . * X * . X X -
|
||||
- - - - - - - - X . * . . * X - -
|
||||
- - - - - - - - X X * . * . X - -
|
||||
X X X X X X X X X . * . X . X X X
|
||||
X % % % % . . X X . * . . * . . X
|
||||
X X % % % . . . . * . . * . . . X
|
||||
X % % % % . . X X X X X X X X X X
|
||||
X X X X X X X X - - - - - - - - -
|
@ -1,5 +1,5 @@
|
||||
use ggez::{Context, audio};
|
||||
use ggez::audio::SoundSource;
|
||||
use ggez::{audio, Context};
|
||||
use specs::{World, WorldExt};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
@ -6,8 +6,6 @@ use std::fmt::Display;
|
||||
pub enum BoxColor {
|
||||
Red,
|
||||
Blue,
|
||||
Green,
|
||||
Brown,
|
||||
}
|
||||
|
||||
impl Display for BoxColor {
|
||||
@ -15,8 +13,6 @@ impl Display for BoxColor {
|
||||
fmt.write_str(match self {
|
||||
BoxColor::Red => "red",
|
||||
BoxColor::Blue => "blue",
|
||||
BoxColor::Green => "green",
|
||||
BoxColor::Brown => "brown",
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
|
@ -1,3 +1,3 @@
|
||||
pub const TILE_WIDTH: f32 = 32.0;
|
||||
pub const MAP_WIDTH: u8 = 22;
|
||||
pub const MAP_HEIGHT: u8 = 11;
|
||||
pub const MAP_WIDTH: u8 = 8;
|
||||
pub const MAP_HEIGHT: u8 = 9;
|
||||
|
@ -45,8 +45,11 @@ pub fn create_floor(world: &mut World, position: Position) {
|
||||
}
|
||||
|
||||
pub fn create_box(world: &mut World, position: Position, color: BoxColor) {
|
||||
let path = format!("/images/box_{}.png", color);
|
||||
static_entity(world, position, 10, &path)
|
||||
let mut sprites: Vec<String> = vec![];
|
||||
for x in 1..=2 {
|
||||
sprites.push(format!("/images/box_{}_{}.png", color, x));
|
||||
}
|
||||
animated_entity(world, position, 10, sprites)
|
||||
.with(Box { color })
|
||||
.with(Movable)
|
||||
.build();
|
||||
|
@ -1,7 +1,7 @@
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
// Fired when the player hits an obstacle like a wall
|
||||
PlayerHitObstacle,
|
||||
PlayerHistObstacle,
|
||||
|
||||
// Fired when an entity is moved
|
||||
EntityMoved(EntityMoved),
|
||||
|
48
src/main.rs
@ -3,9 +3,6 @@ use ggez::event::KeyCode;
|
||||
use ggez::event::KeyMods;
|
||||
use ggez::{conf, event, timer, Context, GameResult};
|
||||
use specs::{RunNow, World, WorldExt};
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path;
|
||||
|
||||
mod audio;
|
||||
@ -58,7 +55,7 @@ impl event::EventHandler for Game {
|
||||
}
|
||||
|
||||
fn draw(&mut self, context: &mut Context) -> GameResult {
|
||||
// Render game entities
|
||||
// Render gaem entities
|
||||
{
|
||||
let mut rs = RenderingSystem { context };
|
||||
rs.run_now(&self.world);
|
||||
@ -69,44 +66,37 @@ impl event::EventHandler for Game {
|
||||
|
||||
fn key_down_event(
|
||||
&mut self,
|
||||
context: &mut Context,
|
||||
_context: &mut Context,
|
||||
keycode: KeyCode,
|
||||
keymod: KeyMods,
|
||||
_keymod: KeyMods,
|
||||
_repeat: bool,
|
||||
) {
|
||||
// println!("Key pressed: {:?}, {:?}", keycode, _keymod);
|
||||
|
||||
match (keycode, keymod) {
|
||||
// Map common keys to quit
|
||||
(KeyCode::Escape, KeyMods::NONE)
|
||||
| (KeyCode::Q, KeyMods::CTRL)
|
||||
| (KeyCode::Q, KeyMods::LOGO) => ggez::event::quit(context),
|
||||
_ => {
|
||||
let mut input_queue = self.world.write_resource::<InputQueue>();
|
||||
input_queue.keys_pressed.push(keycode);
|
||||
}
|
||||
}
|
||||
let mut input_queue = self.world.write_resource::<InputQueue>();
|
||||
input_queue.keys_pressed.push(keycode);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_level(world: &mut World, level: u32) {
|
||||
let map_file = format!("resources/maps/{:02}.txt", level);
|
||||
pub fn initialize_level(world: &mut World) {
|
||||
const MAP: &str = "
|
||||
N N W W W W W W
|
||||
W W W . . . . W
|
||||
W . . . BB . . W
|
||||
W . . RB . . . W
|
||||
W . P . . . . W
|
||||
W . . . . RS . W
|
||||
W . . BS . . . W
|
||||
W . . . . . . W
|
||||
W W W W W W W W
|
||||
";
|
||||
|
||||
let mut file = File::open(&map_file).expect("Failed to open map file");
|
||||
let mut map = String::new();
|
||||
file.read_to_string(&mut map)
|
||||
.expect("failed to read map file");
|
||||
|
||||
load_map(world, map);
|
||||
load_map(world, MAP.to_string());
|
||||
}
|
||||
|
||||
pub fn main() -> GameResult {
|
||||
let mut world = World::new();
|
||||
register_components(&mut world);
|
||||
register_resources(&mut world);
|
||||
|
||||
// @TODO multiple levels
|
||||
initialize_level(&mut world, 1);
|
||||
initialize_level(&mut world);
|
||||
|
||||
// Create a game context and event loop
|
||||
let context_builder = ggez::ContextBuilder::new("rust_sokoban", "Timothy J. Warren")
|
||||
|
18
src/map.rs
@ -16,31 +16,31 @@ pub fn load_map(world: &mut World, map_string: String) {
|
||||
// Figure out which object to create
|
||||
match *column {
|
||||
"." => create_floor(world, position),
|
||||
"X" => {
|
||||
"W" => {
|
||||
create_floor(world, position);
|
||||
create_wall(world, position);
|
||||
}
|
||||
"@" => {
|
||||
"P" => {
|
||||
create_floor(world, position);
|
||||
create_player(world, position);
|
||||
}
|
||||
"*" => {
|
||||
"BB" => {
|
||||
create_floor(world, position);
|
||||
create_box(world, position, BoxColor::Brown);
|
||||
create_box(world, position, BoxColor::Blue);
|
||||
}
|
||||
"+" => {
|
||||
"RB" => {
|
||||
create_floor(world, position);
|
||||
create_box(world, position, BoxColor::Red);
|
||||
}
|
||||
"%" => {
|
||||
"BS" => {
|
||||
create_floor(world, position);
|
||||
create_box_spot(world, position, BoxColor::Brown);
|
||||
create_box_spot(world, position, BoxColor::Blue);
|
||||
}
|
||||
"=" => {
|
||||
"RS" => {
|
||||
create_floor(world, position);
|
||||
create_box_spot(world, position, BoxColor::Red);
|
||||
}
|
||||
"-" => (),
|
||||
"N" => (),
|
||||
c => panic!("unrecognized map item {}", c),
|
||||
}
|
||||
}
|
||||
|
@ -28,29 +28,26 @@ impl<'a> System<'a> for EventSystem {
|
||||
let mut new_events = Vec::new();
|
||||
|
||||
for event in event_queue.events.drain(..) {
|
||||
// println!("New event: {:?}", event);
|
||||
println!("New event: {:?}", event);
|
||||
|
||||
match event {
|
||||
Event::PlayerHitObstacle => {
|
||||
// play sound here
|
||||
Event::PlayerHistObstacle => {
|
||||
// play sound here
|
||||
audio_store.play_sound(&"wall".to_string());
|
||||
}
|
||||
Event::EntityMoved(EntityMoved { id }) => {
|
||||
// An entity was just moved, check if it was a box and fire
|
||||
// more events if it's been moved on a spot.
|
||||
if let Some(the_box) = boxes.get(entities.entity(id)) {
|
||||
let box_spots_with_positions: HashMap<(u8, u8), &BoxSpot> =
|
||||
(&box_spots, &positions)
|
||||
.join()
|
||||
.map(|t| ((t.1.x, t.1.y), t.0))
|
||||
.collect();
|
||||
let box_spots_with_positions: HashMap<(u8, u8), &BoxSpot> = (&box_spots, &positions)
|
||||
.join()
|
||||
.map(|t| ((t.1.x, t.1.y), t.0))
|
||||
.collect();
|
||||
|
||||
if let Some(box_position) = positions.get(entities.entity(id)) {
|
||||
// Check if there is a spot on this position, and if there
|
||||
// is, if it's the correct or incorrect type
|
||||
if let Some(box_spot) =
|
||||
box_spots_with_positions.get(&(box_position.x, box_position.y))
|
||||
{
|
||||
if let Some(box_spot) = box_spots_with_positions.get(&(box_position.x, box_position.y)) {
|
||||
new_events.push(Event::BoxPlacedOnSpot(BoxPlacedOnSpot {
|
||||
is_correct_spot: (box_spot.color == the_box.color),
|
||||
}));
|
||||
|
@ -88,7 +88,7 @@ impl<'a> System<'a> for InputSystem {
|
||||
match immov.get(&pos) {
|
||||
Some(_) => {
|
||||
to_move.clear();
|
||||
events.events.push(Event::PlayerHitObstacle {})
|
||||
events.events.push(Event::PlayerHistObstacle {})
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use ggez::graphics::spritebatch::SpriteBatch;
|
||||
use ggez::graphics::Image;
|
||||
use ggez::graphics::{Color, DrawParam};
|
||||
use ggez::{graphics, Context};
|
||||
use ggez::{nalgebra as na, timer};
|
||||
use ggez::{graphics, Context};
|
||||
use ggez::graphics::spritebatch::SpriteBatch;
|
||||
use itertools::Itertools;
|
||||
use specs::{Join, Read, ReadStorage, System};
|
||||
|
||||
@ -94,8 +94,8 @@ impl<'a> System<'a> for RenderingSystem<'a> {
|
||||
// Iterate spritebatches ordered by z and actually render each of them
|
||||
for (_z, group) in rendering_batches
|
||||
.iter()
|
||||
.sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
|
||||
{
|
||||
.sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) {
|
||||
|
||||
for (image_path, draw_params) in group {
|
||||
let image = Image::new(self.context, image_path).expect("expected image");
|
||||
let mut sprite_batch = SpriteBatch::new(image);
|
||||
|