Compare commits

...

12 Commits

Author SHA1 Message Date
Timothy Warren 9198ca096b Boxes don't need animation 2020-07-28 10:04:44 -04:00
Timothy Warren 73a0b08cfd Use colored sprites 2020-07-28 10:04:02 -04:00
Timothy Warren fb88354571 Create more maps 2020-07-27 16:48:38 -04:00
Timothy Warren 6058f23308 Fix another typo 2020-07-27 16:48:26 -04:00
Timothy Warren f72be8c45d Fix some typos 2020-07-27 16:21:19 -04:00
Timothy Warren 63ab324052 Map out common key combinations to quit 2020-07-27 16:19:32 -04:00
Timothy Warren 86872aaaf9 Cleanup unused sprites 2020-07-27 16:18:38 -04:00
Timothy Warren 526e65da38 Merge pull request 'Load level from file' (#1) from develop into master
Reviewed-on: timw4mail/rust-sokoban#1
2020-07-27 14:37:20 -04:00
Timothy Warren 6b59710964 Load level from file 2020-07-27 14:30:34 -04:00
Timothy Warren 9e0b822dfc Messing with maps 2020-07-27 12:09:55 -04:00
Timothy Warren e57be66c5e Add reference maps 2020-07-27 11:49:42 -04:00
Timothy Warren 007165ba66 Use classic first map 2020-07-27 11:37:35 -04:00
44 changed files with 1507 additions and 51 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 B

BIN
resources/images/box_blue.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

BIN
resources/images/box_brown.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/images/box_green.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
resources/images/box_red.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 761 B

BIN
resources/images/box_spot_blue.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
resources/images/box_spot_red.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
resources/images/floor.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

View File

Before

Width:  |  Height:  |  Size: 234 B

After

Width:  |  Height:  |  Size: 234 B

View File

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

View File

Before

Width:  |  Height:  |  Size: 234 B

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

BIN
resources/images/player_1.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
resources/images/player_2.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
resources/images/player_3.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
resources/images/wall.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 B

After

Width:  |  Height:  |  Size: 740 B

1411
resources/maps.txt Normal file

File diff suppressed because it is too large Load Diff

11
resources/maps/01.txt Normal file
View File

@ -0,0 +1,11 @@
- - - - 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 - - - - - - - - - -

10
resources/maps/02.txt Normal file
View File

@ -0,0 +1,10 @@
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

10
resources/maps/03.txt Normal file
View File

@ -0,0 +1,10 @@
- - - - - - - - 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 - - - - - - - - -

View File

@ -1,5 +1,5 @@
use ggez::{Context, audio};
use ggez::audio::SoundSource;
use ggez::{audio, Context};
use specs::{World, WorldExt};
use std::collections::HashMap;
@ -30,4 +30,4 @@ pub fn initialize_sounds(world: &mut World, context: &mut Context) {
audio_store.sounds.insert(sound_name, sound_source);
}
}
}

View File

@ -6,6 +6,8 @@ use std::fmt::Display;
pub enum BoxColor {
Red,
Blue,
Green,
Brown,
}
impl Display for BoxColor {
@ -13,6 +15,8 @@ impl Display for BoxColor {
fmt.write_str(match self {
BoxColor::Red => "red",
BoxColor::Blue => "blue",
BoxColor::Green => "green",
BoxColor::Brown => "brown",
})?;
Ok(())

View File

@ -1,3 +1,3 @@
pub const TILE_WIDTH: f32 = 32.0;
pub const MAP_WIDTH: u8 = 8;
pub const MAP_HEIGHT: u8 = 9;
pub const MAP_WIDTH: u8 = 22;
pub const MAP_HEIGHT: u8 = 11;

View File

@ -45,11 +45,8 @@ pub fn create_floor(world: &mut World, position: Position) {
}
pub fn create_box(world: &mut World, position: Position, color: BoxColor) {
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)
let path = format!("/images/box_{}.png", color);
static_entity(world, position, 10, &path)
.with(Box { color })
.with(Movable)
.build();

View File

@ -1,7 +1,7 @@
#[derive(Debug)]
pub enum Event {
// Fired when the player hits an obstacle like a wall
PlayerHistObstacle,
PlayerHitObstacle,
// Fired when an entity is moved
EntityMoved(EntityMoved),

View File

@ -3,6 +3,9 @@ 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;
@ -55,7 +58,7 @@ impl event::EventHandler for Game {
}
fn draw(&mut self, context: &mut Context) -> GameResult {
// Render gaem entities
// Render game entities
{
let mut rs = RenderingSystem { context };
rs.run_now(&self.world);
@ -66,37 +69,44 @@ 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,
) {
let mut input_queue = self.world.write_resource::<InputQueue>();
input_queue.keys_pressed.push(keycode);
// 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);
}
}
}
}
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
";
pub fn initialize_level(world: &mut World, level: u32) {
let map_file = format!("resources/maps/{:02}.txt", level);
load_map(world, MAP.to_string());
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);
}
pub fn main() -> GameResult {
let mut world = World::new();
register_components(&mut world);
register_resources(&mut world);
initialize_level(&mut world);
// @TODO multiple levels
initialize_level(&mut world, 1);
// Create a game context and event loop
let context_builder = ggez::ContextBuilder::new("rust_sokoban", "Timothy J. Warren")

View File

@ -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),
"W" => {
"X" => {
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::Blue);
create_box(world, position, BoxColor::Brown);
}
"RB" => {
"+" => {
create_floor(world, position);
create_box(world, position, BoxColor::Red);
}
"BS" => {
"%" => {
create_floor(world, position);
create_box_spot(world, position, BoxColor::Blue);
create_box_spot(world, position, BoxColor::Brown);
}
"RS" => {
"=" => {
create_floor(world, position);
create_box_spot(world, position, BoxColor::Red);
}
"N" => (),
"-" => (),
c => panic!("unrecognized map item {}", c),
}
}

View File

@ -28,26 +28,29 @@ 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::PlayerHistObstacle => {
// play sound here
Event::PlayerHitObstacle => {
// 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),
}));

View File

@ -88,7 +88,7 @@ impl<'a> System<'a> for InputSystem {
match immov.get(&pos) {
Some(_) => {
to_move.clear();
events.events.push(Event::PlayerHistObstacle {})
events.events.push(Event::PlayerHitObstacle {})
}
None => break,
}

View File

@ -1,8 +1,8 @@
use ggez::graphics::spritebatch::SpriteBatch;
use ggez::graphics::Image;
use ggez::graphics::{Color, DrawParam};
use ggez::{nalgebra as na, timer};
use ggez::{graphics, Context};
use ggez::graphics::spritebatch::SpriteBatch;
use ggez::{nalgebra as na, timer};
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);