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)]
pub struct Player {
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_derive::Component;
@ -6,3 +7,9 @@ pub struct Position {
pub x: 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 map::{Map, TileType};
use resources::{Clock, LevelNumber, ShowDebugInfo};
use resources::{Clock, LevelNumber, ShowDebugInfo, Stats};
use sound::SoundSystem;
use sound_effects::SoundEffects;
use specs::prelude::*;
@ -178,6 +178,13 @@ fn main() -> BError {
ticks: 0,
});
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::<Renderable>();
@ -225,11 +232,6 @@ fn main() -> BError {
})
.with(Player {
last_moved: Instant::now(),
score: 1290,
gems: 14,
whips: 7,
teleports: 0,
keys: 0,
})
.build();

View file

@ -7,6 +7,7 @@ use bracket_lib::{prelude::*, random::RandomNumberGenerator};
#[derive(PartialEq, Copy, Clone)]
pub enum TileType {
Wall,
BreakableWall,
Floor,
}
@ -35,8 +36,10 @@ impl Map {
let mut tiles = vec![TileType::Floor; MAP_SIZE];
let mut rng = RandomNumberGenerator::new();
for tile in &mut tiles {
if rng.roll_dice(1, 4) < 2 {
if rng.roll_dice(1, 16) < 2 {
*tile = TileType::Wall;
} else if rng.roll_dice(1, 16) < 2 {
*tile = TileType::BreakableWall;
}
}
Self {
@ -78,7 +81,7 @@ impl Map {
to_cp437(' '),
);
}
TileType::Wall => {
TileType::BreakableWall => {
ctx.set(
x + MAP_X,
y + MAP_Y,
@ -87,15 +90,33 @@ impl Map {
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)]
}
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 {
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;
}
}
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::resources::{Clock, ShowDebugInfo};
use crate::resources::{Clock, LevelNumber, ShowDebugInfo, Stats};
use crate::vga_color as vga;
use crate::{LevelNumber, Player};
use bracket_lib::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 + 4, SIDEBAR_POS_Y + 15, "Keys");
let players = ecs.read_storage::<Player>();
for player in players.join() {
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, player.gems);
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, player.teleports);
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 16, player.keys);
}
let stats = ecs.read_resource::<Stats>();
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 + 7, stats.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 + 13, stats.teleports);
ctx.print_centered_at(SIDEBAR_POS_X + 6, SIDEBAR_POS_Y + 16, stats.keys);
// Hotkey list
ctx.print_color(

View file

@ -3,8 +3,8 @@ use crate::{
monster::{self, ticks_for_kind},
Monster, Position, Renderable,
},
map::Map,
resources::Clock,
map::{Map, TileType},
resources::{Clock, Stats},
};
use bracket_lib::{prelude::*, random::RandomNumberGenerator};
use specs::prelude::*;
@ -14,9 +14,11 @@ pub struct MonsterMotion {}
#[allow(clippy::type_complexity)]
impl<'a> System<'a> for MonsterMotion {
type SystemData = (
Entities<'a>,
ReadExpect<'a, Clock>,
ReadExpect<'a, Point>,
ReadExpect<'a, Map>,
WriteExpect<'a, Map>,
WriteExpect<'a, Stats>,
WriteStorage<'a, Monster>,
WriteStorage<'a, Position>,
WriteStorage<'a, Renderable>,
@ -24,9 +26,19 @@ impl<'a> System<'a> for MonsterMotion {
fn run(
&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 {
monster.ticks_until_move -= 1;
@ -57,10 +69,26 @@ impl<'a> System<'a> for MonsterMotion {
x: position.x + delta_x,
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.y = destination.y;
}
}
monster.ticks_until_move = ticks_for_kind(monster.kind);
}
}