Compare commits

..

4 commits

Author SHA1 Message Date
82c4358ac7 Allow monsters to break blocks
All checks were successful
continuous-integration/drone/push Build is passing
2022-02-01 03:01:21 -05:00
b62f2759de Add score for touching/whipping monsters 2022-02-01 02:56:45 -05:00
b2672904c8 Add monster impact sfx 2022-02-01 02:54:08 -05:00
73aa491d24 Fix monster/player collision issues 2022-02-01 02:53:00 -05:00
8 changed files with 105 additions and 40 deletions

View file

@ -1,4 +1,7 @@
use crate::vga_color as vga; use crate::{
resources::{sound_output::SoundSamples, SoundEffects},
vga_color as vga,
};
use bracket_lib::prelude::*; use bracket_lib::prelude::*;
use specs::prelude::*; use specs::prelude::*;
use specs_derive::Component; use specs_derive::Component;
@ -47,3 +50,11 @@ pub fn damage_for_kind(kind: MonsterKind) -> u32 {
MonsterKind::Fast => 3, MonsterKind::Fast => 3,
} }
} }
pub fn sound_effect_for_kind(kind: MonsterKind, sound_effects: &SoundEffects) -> SoundSamples {
match kind {
MonsterKind::Slow => sound_effects.slow_hit.clone(),
MonsterKind::Medium => sound_effects.medium_hit.clone(),
MonsterKind::Fast => sound_effects.fast_hit.clone(),
}
}

View file

@ -61,7 +61,7 @@ fn main() -> BError {
ecs.register::<Player>(); ecs.register::<Player>();
ecs.register::<WantsToWhip>(); ecs.register::<WantsToWhip>();
let map = Map::from_level(levels::get_level(starting_level)); let mut map = Map::from_level(levels::get_level(starting_level));
map.spawn_entities(&mut ecs); map.spawn_entities(&mut ecs);
ecs.insert(map); ecs.insert(map);

View file

@ -80,9 +80,14 @@ impl Map {
} }
} }
pub fn spawn_entities(&self, ecs: &mut World) { pub fn spawn_entities(&mut self, ecs: &mut World) {
for (index, tile) in self.tiles.iter().enumerate() { for (index, tile) in self
let point = self.index_to_point2d(index); .tiles
.iter_mut()
.enumerate()
.collect::<Vec<(usize, &mut TileType)>>()
{
let point = Point::new(index % MAP_WIDTH, index / MAP_WIDTH);
match tile { match tile {
TileType::Player => { TileType::Player => {
let player_entity = ecs let player_entity = ecs
@ -102,6 +107,7 @@ impl Map {
.build(); .build();
ecs.insert(point); ecs.insert(point);
ecs.insert(player_entity); ecs.insert(player_entity);
self.tile_content[index] = Some(player_entity);
} }
TileType::Slow => { TileType::Slow => {
let mut rng = RandomNumberGenerator::new(); let mut rng = RandomNumberGenerator::new();
@ -174,15 +180,18 @@ impl Map {
}); });
} }
pub fn get_tile_content(&self, index: usize) -> Option<Entity> { pub fn get_tile_content_at(&self, point: Point) -> Option<Entity> {
let index = self.point2d_to_index(point);
self.tile_content[index] self.tile_content[index]
} }
pub fn set_tile_content(&mut self, index: usize, entity: Entity) { pub fn set_tile_content_at(&mut self, point: Point, entity: Entity) {
let index = self.point2d_to_index(point);
self.tile_content[index] = Some(entity); self.tile_content[index] = Some(entity);
} }
pub fn clear_tile_content(&mut self, index: usize) { pub fn clear_tile_content_at(&mut self, point: Point) {
let index = self.point2d_to_index(point);
self.tile_content[index] = None; self.tile_content[index] = None;
} }
@ -227,6 +236,11 @@ impl Map {
self.tiles[self.point2d_to_index(point)] self.tiles[self.point2d_to_index(point)]
} }
pub fn get_tile_at_mut(&mut self, point: Point) -> &mut TileType {
let index = self.point2d_to_index(point);
&mut self.tiles[index]
}
pub fn set_tile_at(&mut self, point: Point, tile: TileType) { pub fn set_tile_at(&mut self, point: Point, tile: TileType) {
let index = self.point2d_to_index(point); let index = self.point2d_to_index(point);
self.tiles[index] = tile; self.tiles[index] = tile;

View file

@ -70,4 +70,8 @@ impl Stats {
true true
} }
} }
pub fn add_score(&mut self, score: u32) {
self.score += score;
}
} }

View file

@ -35,19 +35,22 @@ pub struct SoundEffects {
pub whipping: SoundSamples, pub whipping: SoundSamples,
pub whipping_hit: SoundSamples, pub whipping_hit: SoundSamples,
pub whipping_hit_end: SoundSamples, pub whipping_hit_end: SoundSamples,
pub slow_hit: SoundSamples,
pub medium_hit: SoundSamples,
pub fast_hit: SoundSamples,
rng: RandomNumberGenerator, rng: RandomNumberGenerator,
} }
impl SoundEffects { impl SoundEffects {
pub fn new(ss: &SoundOutput) -> Self { pub fn new(sound_output: &SoundOutput) -> Self {
Self { Self {
startup: ss.render_sound_effect(&SoundEffect { startup: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![Sound { sounds: vec![Sound {
sound_type: SoundType::Sweep(1, 350), sound_type: SoundType::Sweep(1, 350),
duration: Duration::from_secs(1), duration: Duration::from_secs(1),
}], }],
}), }),
step: ss.render_sound_effect(&SoundEffect { step: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![ sounds: vec![
Sound { Sound {
sound_type: SoundType::Noise(350, 900), sound_type: SoundType::Noise(350, 900),
@ -63,7 +66,7 @@ impl SoundEffects {
}, },
], ],
}), }),
pickup: ss.render_sound_effect(&SoundEffect { pickup: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![ sounds: vec![
Sound { Sound {
sound_type: SoundType::Noise(350, 900), sound_type: SoundType::Noise(350, 900),
@ -79,7 +82,7 @@ impl SoundEffects {
}, },
], ],
}), }),
bad_key: ss.render_sound_effect(&SoundEffect { bad_key: sound_output.render_sound_effect(&SoundEffect {
sounds: iter::once(Sound { sounds: iter::once(Sound {
sound_type: SoundType::Tone(540), sound_type: SoundType::Tone(540),
duration: Duration::from_millis(40), duration: Duration::from_millis(40),
@ -98,7 +101,7 @@ impl SoundEffects {
})) }))
.collect(), .collect(),
}), }),
blocked: ss.render_sound_effect(&SoundEffect { blocked: sound_output.render_sound_effect(&SoundEffect {
sounds: (30..=60) sounds: (30..=60)
.rev() .rev()
.step_by(6) .step_by(6)
@ -108,13 +111,13 @@ impl SoundEffects {
}) })
.collect(), .collect(),
}), }),
whipping: ss.render_sound_effect(&SoundEffect { whipping: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![Sound { sounds: vec![Sound {
sound_type: SoundType::Tone(70), sound_type: SoundType::Tone(70),
duration: Duration::from_secs(3), duration: Duration::from_secs(3),
}], }],
}), }),
whipping_hit: ss.render_sound_effect(&SoundEffect { whipping_hit: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![ sounds: vec![
Sound { Sound {
sound_type: SoundType::Tone(400), sound_type: SoundType::Tone(400),
@ -126,12 +129,30 @@ impl SoundEffects {
}, },
], ],
}), }),
whipping_hit_end: ss.render_sound_effect(&SoundEffect { whipping_hit_end: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![Sound { sounds: vec![Sound {
sound_type: SoundType::Tone(400), sound_type: SoundType::Tone(400),
duration: Duration::from_millis(20), duration: Duration::from_millis(20),
}], }],
}), }),
slow_hit: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![Sound {
sound_type: SoundType::Tone(400),
duration: Duration::from_millis(25),
}],
}),
medium_hit: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![Sound {
sound_type: SoundType::Tone(600),
duration: Duration::from_millis(25),
}],
}),
fast_hit: sound_output.render_sound_effect(&SoundEffect {
sounds: vec![Sound {
sound_type: SoundType::Tone(800),
duration: Duration::from_millis(25),
}],
}),
rng: RandomNumberGenerator::new(), rng: RandomNumberGenerator::new(),
} }
} }

View file

@ -1,6 +1,7 @@
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::components::monster::damage_for_kind; use crate::components::monster::damage_for_kind;
use crate::components::monster::sound_effect_for_kind;
use crate::components::*; use crate::components::*;
use crate::resources::*; use crate::resources::*;
use crate::systems::*; use crate::systems::*;
@ -119,7 +120,7 @@ impl State {
let monsters = self.ecs.write_storage::<Monster>(); let monsters = self.ecs.write_storage::<Monster>();
let mut map = self.ecs.write_resource::<Map>(); let mut map = self.ecs.write_resource::<Map>();
let mut stats = self.ecs.write_resource::<Stats>(); let mut stats = self.ecs.write_resource::<Stats>();
let mut sound_system = self.ecs.write_resource::<SoundOutput>(); let mut sound_output = self.ecs.write_resource::<SoundOutput>();
let wants_to_whips = self.ecs.read_storage::<WantsToWhip>(); let wants_to_whips = self.ecs.read_storage::<WantsToWhip>();
for (player_entity, player, pos) in (&entities, &mut players, &mut positions).join() { for (player_entity, player, pos) in (&entities, &mut players, &mut positions).join() {
@ -139,17 +140,21 @@ impl State {
if map.in_bounds(destination) { if map.in_bounds(destination) {
if map.is_solid(destination) { if map.is_solid(destination) {
sound_system.play_sound(sound_effects.blocked.clone()); sound_output.play_sound(sound_effects.blocked.clone());
} else { } else {
if let Some(e) = map.get_tile_content(map.point2d_to_index(destination)) { if let Some(e) = map.get_tile_content_at(destination) {
if let Some(monster) = monsters.get(e) { if let Some(monster) = monsters.get(e) {
stats.add_score(damage_for_kind(monster.kind));
stats.take_gems(damage_for_kind(monster.kind)); stats.take_gems(damage_for_kind(monster.kind));
sound_output.play_sound(sound_effect_for_kind(
monster.kind,
&sound_effects,
));
let _ = entities.delete(e); let _ = entities.delete(e);
} }
} }
let index = map.point2d_to_index(Point::from(*pos)); map.clear_tile_content_at(Point::from(*pos));
map.clear_tile_content(index);
pos.x = destination.x; pos.x = destination.x;
pos.y = destination.y; pos.y = destination.y;
@ -158,16 +163,15 @@ impl State {
player_pos.x = pos.x; player_pos.x = pos.x;
player_pos.y = pos.y; player_pos.y = pos.y;
let index = map.point2d_to_index(destination); map.set_tile_content_at(destination, player_entity);
map.set_tile_content(index, player_entity);
self.ecs.write_resource::<Clock>().force_tick(); self.ecs.write_resource::<Clock>().force_tick();
sound_system.play_sound(sound_effects.step.clone()); sound_output.play_sound(sound_effects.step.clone());
} }
} else { } else {
let static_sound = sound_effects.get_new_static_effect(&sound_system); let static_sound = sound_effects.get_new_static_effect(&sound_output);
sound_system.play_sound(static_sound); sound_output.play_sound(static_sound);
} }
player.last_moved = now; player.last_moved = now;

View file

@ -1,9 +1,9 @@
use crate::{ use crate::{
components::{ components::{
monster::{self, damage_for_kind, ticks_for_kind}, monster::{self, damage_for_kind, sound_effect_for_kind, ticks_for_kind},
Monster, Player, Position, Renderable, Monster, Player, Position, Renderable,
}, },
resources::{Clock, Map, Stats}, resources::{Clock, Map, SoundEffects, SoundOutput, Stats},
tile_data::TileType, tile_data::TileType,
}; };
use bracket_lib::{prelude::*, random::RandomNumberGenerator}; use bracket_lib::{prelude::*, random::RandomNumberGenerator};
@ -19,6 +19,8 @@ impl<'a> System<'a> for MonsterAiSystem {
ReadExpect<'a, Point>, ReadExpect<'a, Point>,
WriteExpect<'a, Map>, WriteExpect<'a, Map>,
WriteExpect<'a, Stats>, WriteExpect<'a, Stats>,
ReadExpect<'a, SoundEffects>,
WriteExpect<'a, SoundOutput>,
WriteStorage<'a, Monster>, WriteStorage<'a, Monster>,
WriteStorage<'a, Position>, WriteStorage<'a, Position>,
WriteStorage<'a, Renderable>, WriteStorage<'a, Renderable>,
@ -33,6 +35,8 @@ impl<'a> System<'a> for MonsterAiSystem {
player_pos, player_pos,
mut map, mut map,
mut stats, mut stats,
sound_effects,
mut sound_output,
mut monsters, mut monsters,
mut positions, mut positions,
mut renderables, mut renderables,
@ -74,26 +78,29 @@ impl<'a> System<'a> for MonsterAiSystem {
y: position.y + delta_y, y: position.y + delta_y,
}; };
if let Some(e) = map.get_tile_content(map.point2d_to_index(destination)) { if let Some(e) = map.get_tile_content_at(destination) {
if let Some(_player) = players.get(e) { if let Some(_player) = players.get(e) {
// TODO: Sound // TODO: Sound
map.clear_tile_content_at(Point::from(**position));
stats.take_gems(damage_for_kind(monster.kind)); stats.take_gems(damage_for_kind(monster.kind));
sound_output
.play_sound(sound_effect_for_kind(monster.kind, &sound_effects));
let _ = entities.delete(*entity); let _ = entities.delete(*entity);
} }
} else { } else {
match map.get_tile_at(destination) { let tile = map.get_tile_at_mut(destination);
match tile {
TileType::Wall => {} TileType::Wall => {}
TileType::Block => { TileType::Block => {
// TODO: Sound // TODO: Sound
*tile = TileType::Floor;
let _ = entities.delete(*entity); let _ = entities.delete(*entity);
} }
_ => { _ => {
let index = map.point2d_to_index(Point::from(**position)); map.clear_tile_content_at(Point::from(**position));
map.clear_tile_content(index);
position.x = destination.x; position.x = destination.x;
position.y = destination.y; position.y = destination.y;
let index = map.point2d_to_index(destination); map.set_tile_content_at(destination, *entity);
map.set_tile_content(index, *entity);
} }
} }
} }

View file

@ -4,8 +4,8 @@ use bracket_lib::prelude::*;
use specs::prelude::*; use specs::prelude::*;
use crate::{ use crate::{
components::{Monster, Position, WantsToWhip}, components::{monster::damage_for_kind, Monster, Position, WantsToWhip},
resources::{Map, SoundEffects, SoundOutput, StopClock}, resources::{Map, SoundEffects, SoundOutput, Stats, StopClock},
}; };
pub struct WhipSystem {} pub struct WhipSystem {}
@ -17,6 +17,7 @@ impl<'a> System<'a> for WhipSystem {
WriteExpect<'a, StopClock>, WriteExpect<'a, StopClock>,
WriteExpect<'a, SoundOutput>, WriteExpect<'a, SoundOutput>,
ReadExpect<'a, SoundEffects>, ReadExpect<'a, SoundEffects>,
WriteExpect<'a, Stats>,
ReadStorage<'a, Position>, ReadStorage<'a, Position>,
WriteStorage<'a, WantsToWhip>, WriteStorage<'a, WantsToWhip>,
WriteStorage<'a, Monster>, WriteStorage<'a, Monster>,
@ -25,10 +26,11 @@ impl<'a> System<'a> for WhipSystem {
fn run(&mut self, data: Self::SystemData) { fn run(&mut self, data: Self::SystemData) {
let ( let (
map, mut map,
mut stop_clock, mut stop_clock,
mut sound_output, mut sound_output,
sound_effects, sound_effects,
mut stats,
positions, positions,
mut wants_to_whips, mut wants_to_whips,
monsters, monsters,
@ -92,9 +94,11 @@ impl<'a> System<'a> for WhipSystem {
}; };
if let Some(dest) = destination { if let Some(dest) = destination {
if let Some(e) = map.get_tile_content(map.point2d_to_index(dest)) { if let Some(e) = map.get_tile_content_at(dest) {
if let Some(_monster) = monsters.get(e) { if let Some(monster) = monsters.get(e) {
stats.add_score(damage_for_kind(monster.kind));
let _ = entities.delete(e); let _ = entities.delete(e);
map.clear_tile_content_at(dest);
if let Some(sound) = &mut wants_to_whip.sound { if let Some(sound) = &mut wants_to_whip.sound {
sound.control::<oddio::Stop<_>, _>().stop(); sound.control::<oddio::Stop<_>, _>().stop();
} }