Add breakable walls and monster collision with them

This commit is contained in:
Alex Page 2022-01-26 16:06:27 -05:00
parent c2db40dd6b
commit 9ad3d9de0b
7 changed files with 91 additions and 33 deletions

View file

@ -6,9 +6,4 @@ use specs_derive::Component;
#[derive(Component, Debug)] #[derive(Component, Debug)]
pub struct Player { pub struct Player {
pub last_moved: Instant, pub last_moved: Instant,
pub score: u32,
pub gems: u32,
pub whips: u32,
pub teleports: u32,
pub keys: u32,
} }

View file

@ -1,3 +1,4 @@
use bracket_lib::prelude::*;
use specs::prelude::*; use specs::prelude::*;
use specs_derive::Component; use specs_derive::Component;
@ -6,3 +7,9 @@ pub struct Position {
pub x: i32, pub x: i32,
pub y: i32, pub y: i32,
} }
impl PartialEq<Point> for Position {
fn eq(&self, other: &Point) -> bool {
return self.x == other.x && self.y == other.y;
}
}

View file

@ -17,7 +17,7 @@ use components::{
}; };
use constants::*; use constants::*;
use map::{Map, TileType}; use map::{Map, TileType};
use resources::{Clock, LevelNumber, ShowDebugInfo}; use resources::{Clock, LevelNumber, ShowDebugInfo, Stats};
use sound::SoundSystem; use sound::SoundSystem;
use sound_effects::SoundEffects; use sound_effects::SoundEffects;
use specs::prelude::*; use specs::prelude::*;
@ -178,6 +178,13 @@ fn main() -> BError {
ticks: 0, ticks: 0,
}); });
gs.ecs.insert(sound_effects); gs.ecs.insert(sound_effects);
gs.ecs.insert(Stats {
score: 1290,
gems: 14,
whips: 7,
teleports: 0,
keys: 0,
});
gs.ecs.register::<Position>(); gs.ecs.register::<Position>();
gs.ecs.register::<Renderable>(); gs.ecs.register::<Renderable>();
@ -225,11 +232,6 @@ fn main() -> BError {
}) })
.with(Player { .with(Player {
last_moved: Instant::now(), last_moved: Instant::now(),
score: 1290,
gems: 14,
whips: 7,
teleports: 0,
keys: 0,
}) })
.build(); .build();

View file

@ -7,6 +7,7 @@ use bracket_lib::{prelude::*, random::RandomNumberGenerator};
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]
pub enum TileType { pub enum TileType {
Wall, Wall,
BreakableWall,
Floor, Floor,
} }
@ -35,8 +36,10 @@ impl Map {
let mut tiles = vec![TileType::Floor; MAP_SIZE]; let mut tiles = vec![TileType::Floor; MAP_SIZE];
let mut rng = RandomNumberGenerator::new(); let mut rng = RandomNumberGenerator::new();
for tile in &mut tiles { for tile in &mut tiles {
if rng.roll_dice(1, 4) < 2 { if rng.roll_dice(1, 16) < 2 {
*tile = TileType::Wall; *tile = TileType::Wall;
} else if rng.roll_dice(1, 16) < 2 {
*tile = TileType::BreakableWall;
} }
} }
Self { Self {
@ -78,7 +81,7 @@ impl Map {
to_cp437(' '), to_cp437(' '),
); );
} }
TileType::Wall => { TileType::BreakableWall => {
ctx.set( ctx.set(
x + MAP_X, x + MAP_X,
y + MAP_Y, y + MAP_Y,
@ -87,15 +90,33 @@ impl Map {
to_cp437('▓'), to_cp437('▓'),
); );
} }
TileType::Wall => {
ctx.set(
x + MAP_X,
y + MAP_Y,
RGB::named(vga::YELLOW),
RGB::named(vga::BLACK),
to_cp437('█'),
);
}
} }
} }
} }
pub fn tile_at(&self, point: Point) -> TileType { pub fn get_tile_at(&self, point: Point) -> TileType {
self.tiles[self.point2d_to_index(point)] self.tiles[self.point2d_to_index(point)]
} }
pub fn set_tile_at(&mut self, point: Point, tile: TileType) {
let index = self.point2d_to_index(point);
self.tiles[index] = tile;
}
pub fn is_solid(&self, point: Point) -> bool { pub fn is_solid(&self, point: Point) -> bool {
self.tile_at(point) == TileType::Wall match self.get_tile_at(point) {
TileType::Wall => true,
TileType::BreakableWall => true,
_ => false,
}
} }
} }

View file

@ -32,3 +32,11 @@ impl Clock {
self.ticks += 1; self.ticks += 1;
} }
} }
pub struct Stats {
pub score: u32,
pub gems: u32,
pub whips: u32,
pub teleports: u32,
pub keys: u32,
}

View file

@ -1,7 +1,6 @@
use crate::constants::{SIDEBAR_POS_X, SIDEBAR_POS_Y}; use crate::constants::{SIDEBAR_POS_X, SIDEBAR_POS_Y};
use crate::resources::{Clock, ShowDebugInfo}; use crate::resources::{Clock, LevelNumber, ShowDebugInfo, Stats};
use crate::vga_color as vga; use crate::vga_color as vga;
use crate::{LevelNumber, Player};
use bracket_lib::prelude::*; use bracket_lib::prelude::*;
use specs::prelude::*; use specs::prelude::*;
@ -47,14 +46,12 @@ pub fn draw(ecs: &World, ctx: &mut BTerm) {
ctx.print(SIDEBAR_POS_X + 2, SIDEBAR_POS_Y + 12, "Teleports"); ctx.print(SIDEBAR_POS_X + 2, SIDEBAR_POS_Y + 12, "Teleports");
ctx.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 15, "Keys"); ctx.print(SIDEBAR_POS_X + 4, SIDEBAR_POS_Y + 15, "Keys");
let players = ecs.read_storage::<Player>(); let stats = ecs.read_resource::<Stats>();
for player in players.join() { ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 1, stats.score);
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 1, player.score); ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 7, stats.gems);
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 7, player.gems); ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 10, stats.whips);
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 10, player.whips); ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 13, stats.teleports);
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 13, player.teleports); ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 16, stats.keys);
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 16, player.keys);
}
// Hotkey list // Hotkey list
ctx.print_color( ctx.print_color(

View file

@ -3,8 +3,8 @@ use crate::{
monster::{self, ticks_for_kind}, monster::{self, ticks_for_kind},
Monster, Position, Renderable, Monster, Position, Renderable,
}, },
map::Map, map::{Map, TileType},
resources::Clock, resources::{Clock, Stats},
}; };
use bracket_lib::{prelude::*, random::RandomNumberGenerator}; use bracket_lib::{prelude::*, random::RandomNumberGenerator};
use specs::prelude::*; use specs::prelude::*;
@ -14,9 +14,11 @@ pub struct MonsterMotion {}
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
impl<'a> System<'a> for MonsterMotion { impl<'a> System<'a> for MonsterMotion {
type SystemData = ( type SystemData = (
Entities<'a>,
ReadExpect<'a, Clock>, ReadExpect<'a, Clock>,
ReadExpect<'a, Point>, ReadExpect<'a, Point>,
ReadExpect<'a, Map>, WriteExpect<'a, Map>,
WriteExpect<'a, Stats>,
WriteStorage<'a, Monster>, WriteStorage<'a, Monster>,
WriteStorage<'a, Position>, WriteStorage<'a, Position>,
WriteStorage<'a, Renderable>, WriteStorage<'a, Renderable>,
@ -24,9 +26,19 @@ impl<'a> System<'a> for MonsterMotion {
fn run( fn run(
&mut self, &mut self,
(clock, player_pos, map, mut monster, mut position, mut renderable): Self::SystemData, (
entities,
clock,
player_pos,
mut map,
mut stats,
mut monster,
mut position,
mut renderable,
): Self::SystemData,
) { ) {
for (monster, position, renderable) in (&mut monster, &mut position, &mut renderable).join() for (entity, monster, position, renderable) in
(&entities, &mut monster, &mut position, &mut renderable).join()
{ {
if clock.has_ticked { if clock.has_ticked {
monster.ticks_until_move -= 1; monster.ticks_until_move -= 1;
@ -57,10 +69,26 @@ impl<'a> System<'a> for MonsterMotion {
x: position.x + delta_x, x: position.x + delta_x,
y: position.y + delta_y, y: position.y + delta_y,
}; };
if !map.is_solid(destination) {
if destination == *player_pos {
// TODO: Sound
stats.gems -= 1;
let _ = entities.delete(entity);
}
match map.get_tile_at(destination) {
TileType::Wall => {}
TileType::BreakableWall => {
// TODO: Sound
map.set_tile_at(destination, TileType::Floor);
let _ = entities.delete(entity);
}
TileType::Floor => {
position.x = destination.x; position.x = destination.x;
position.y = destination.y; position.y = destination.y;
} }
}
monster.ticks_until_move = ticks_for_kind(monster.kind); monster.ticks_until_move = ticks_for_kind(monster.kind);
} }
} }