diff --git a/Cargo.lock b/Cargo.lock index 4fbd2e8..6e668a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -778,37 +778,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -[[package]] -name = "fundsp" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44dcde4aedad5675c131b5114d431b4d7c739dc32dd599bf0460f36413d247e" -dependencies = [ - "generic-array", - "lazy_static", - "num-complex", - "numeric-array", - "rsor", - "rustfft", - "tinyvec", -] - [[package]] name = "futures" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" version = "0.2.3" @@ -1049,11 +1024,11 @@ version = "0.1.0" dependencies = [ "bracket-lib", "cpal", - "fundsp", "oddio", + "rand", "specs", "specs-derive", - "typenum", + "spin_sleep", "winres", ] @@ -1438,15 +1413,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "num-complex" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" -dependencies = [ - "num-traits", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -1554,16 +1520,6 @@ dependencies = [ "syn", ] -[[package]] -name = "numeric-array" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c59a9b227913a685ed84aa0de5ded58274e8bcfa55760faae07bc82aee64ccf" -dependencies = [ - "generic-array", - "num-traits", -] - [[package]] name = "objc" version = "0.2.7" @@ -1694,13 +1650,10 @@ dependencies = [ ] [[package]] -name = "primal-check" -version = "0.3.1" +name = "ppv-lite86" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01419cee72c1a1ca944554e23d83e483e1bccf378753344e881de28b5487511d" -dependencies = [ - "num-integer", -] +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "proc-macro-crate" @@ -1745,6 +1698,19 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", "rand_core", ] @@ -1753,6 +1719,18 @@ name = "rand_core" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] [[package]] name = "rand_xorshift" @@ -1808,32 +1786,12 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "rsor" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b57e3964dc31a38416366d2e8f7675755402a10832d5cf4e4112d66ac77cdda" - [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustfft" -version = "6.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d089e5c57521629a59f5f39bca7434849ff89bd6873b521afe389c1c602543" -dependencies = [ - "num-complex", - "num-integer", - "num-traits", - "primal-check", - "strength_reduce", - "transpose", -] - [[package]] name = "rusttype" version = "0.9.2" @@ -2003,12 +1961,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" -[[package]] -name = "strength_reduce" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ff2f71c82567c565ba4b3009a9350a96a7269eaa4001ebedae926230bc2254" - [[package]] name = "strsim" version = "0.9.3" @@ -2046,21 +1998,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tinyvec" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - [[package]] name = "tokio-executor" version = "0.1.10" @@ -2092,16 +2029,6 @@ dependencies = [ "serde", ] -[[package]] -name = "transpose" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95f9c900aa98b6ea43aee227fd680550cdec726526aab8ac801549eadb25e39f" -dependencies = [ - "num-integer", - "strength_reduce", -] - [[package]] name = "ttf-parser" version = "0.6.2" @@ -2123,12 +2050,6 @@ dependencies = [ "nom 5.1.2", ] -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - [[package]] name = "ultraviolet" version = "0.8.1" diff --git a/Cargo.toml b/Cargo.toml index 374353b..6fb9185 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,8 @@ specs = { version = "0.16.1", default-features = false } specs-derive = "0.4.1" cpal = "0.13" oddio = "0.5" -fundsp = "0.1.0" -typenum = "1.15.0" +rand = "0.8" +spin_sleep = "1.0" [target.'cfg(windows)'.build-dependencies] winres = "0.1" diff --git a/src/components/position.rs b/src/components/position.rs index a6f7935..919ab1d 100644 --- a/src/components/position.rs +++ b/src/components/position.rs @@ -2,7 +2,7 @@ use bracket_lib::prelude::*; use specs::prelude::*; use specs_derive::Component; -#[derive(Component, Clone, Copy)] +#[derive(Component)] pub struct Position { pub x: i32, pub y: i32, @@ -13,21 +13,3 @@ impl PartialEq for Position { self.x == other.x && self.y == other.y } } - -impl From for Position { - fn from(point: Point) -> Self { - Self { - x: point.x, - y: point.y, - } - } -} - -impl From for Point { - fn from(position: Position) -> Self { - Self { - x: position.x, - y: position.y, - } - } -} diff --git a/src/resources/map.rs b/src/resources/map.rs index 6628f77..4cbc00c 100644 --- a/src/resources/map.rs +++ b/src/resources/map.rs @@ -182,10 +182,6 @@ impl Map { self.tile_content[index] = Some(entity); } - pub fn clear_tile_content(&mut self, index: usize) { - self.tile_content[index] = None; - } - pub fn get_tiles(&self) -> &Vec { &self.tiles } diff --git a/src/resources/sound_effects.rs b/src/resources/sound_effects.rs index 58d2576..e3f3259 100644 --- a/src/resources/sound_effects.rs +++ b/src/resources/sound_effects.rs @@ -5,15 +5,12 @@ use bracket_lib::random::RandomNumberGenerator; use crate::resources::sound_output::{SoundOutput, SoundSamples}; type Frequency = u32; -type StartFrequency = u32; -type EndFrequency = u32; type MinFrequency = u32; type MaxFrequency = u32; pub enum SoundType { Silence, Tone(Frequency), - Sweep(StartFrequency, EndFrequency), Noise(MinFrequency, MaxFrequency), } @@ -34,7 +31,6 @@ pub struct SoundEffects { pub blocked: SoundSamples, pub whipping: SoundSamples, pub whipping_hit: SoundSamples, - pub whipping_hit_end: SoundSamples, rng: RandomNumberGenerator, } @@ -42,10 +38,13 @@ impl SoundEffects { pub fn new(ss: &SoundOutput) -> Self { Self { startup: ss.render_sound_effect(&SoundEffect { - sounds: vec![Sound { - sound_type: SoundType::Sweep(1, 350), - duration: Duration::from_secs(1), - }], + sounds: (30..400) + .step_by(8) + .map(|x| Sound { + sound_type: SoundType::Tone(x), + duration: Duration::from_millis(24), + }) + .collect(), }), step: ss.render_sound_effect(&SoundEffect { sounds: vec![ @@ -81,8 +80,8 @@ impl SoundEffects { }), bad_key: ss.render_sound_effect(&SoundEffect { sounds: iter::once(Sound { - sound_type: SoundType::Tone(540), - duration: Duration::from_millis(40), + sound_type: SoundType::Tone(400), + duration: Duration::from_millis(20), }) .chain((0..4).flat_map(|_| { array::IntoIter::new([ @@ -126,12 +125,6 @@ impl SoundEffects { }, ], }), - whipping_hit_end: ss.render_sound_effect(&SoundEffect { - sounds: vec![Sound { - sound_type: SoundType::Tone(400), - duration: Duration::from_millis(20), - }], - }), rng: RandomNumberGenerator::new(), } } diff --git a/src/resources/sound_output.rs b/src/resources/sound_output.rs index 96f800e..2dba98a 100644 --- a/src/resources/sound_output.rs +++ b/src/resources/sound_output.rs @@ -1,11 +1,11 @@ -use std::sync::Arc; +use std::{f32::consts::PI, sync::Arc}; use cpal::{ traits::{DeviceTrait, HostTrait, StreamTrait}, SampleRate, Stream, }; -use fundsp::prelude::*; use oddio::{Frames, FramesSignal, Gain, Handle, Mixer, MonoToStereo, Stop}; +use rand::Rng; use super::sound_effects::{SoundEffect, SoundType}; @@ -70,30 +70,43 @@ impl SoundOutput { .map(|_| 0f32) .collect::>(), SoundType::Tone(freq) => { - let mut c = square_hz(freq as f32); - c.reset(Some(self.sample_rate.0 as f64)); + if freq == 0 { + return (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) + as usize) + .map(|_| 0f32) + .collect::>(); + } + let num_harmonics = self.sample_rate.0 / (freq as u32 * 2); + let coefficients = (0..=num_harmonics) + .map(|i| { + if i == 0 { + return 0.0; + } + (i as f32 * 0.5 * PI).sin() * 2.0 / (i as f32 * PI) + }) + .collect::>(); + let scaler = freq as f32 * PI * 2.0 / self.sample_rate.0 as f32; (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize) - .map(|_| c.get_mono()) - .collect::>() - } - SoundType::Sweep(start_freq, end_freq) => { - let mut c = lfo(|t| { - lerp( - start_freq as f32, - end_freq as f32, - t * sound.duration.as_secs_f32(), - ) - }) >> square(); - c.reset(Some(self.sample_rate.0 as f64)); - (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize) - .map(|_| c.get_mono()) + .map(|i| { + let temp = scaler * i as f32; + coefficients + .iter() + .enumerate() + .map(|(j, coef)| coef * (j as f32 * temp).cos()) + .sum::() + }) .collect::>() } SoundType::Noise(min, max) => { - let mut c = - (((white() + dc(1.0)) * dc(max as f32 / 2.0)) + dc(min as f32)) >> square(); (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize) - .map(|_| c.get_mono()) + .map(|i| { + let t = i as f32 / self.sample_rate.0 as f32; + (t * (rand::thread_rng().gen_range(min as f32..max as f32)) + * 2.0 + * std::f32::consts::PI) + .sin() + .signum() + }) .collect::>() } }) @@ -107,7 +120,7 @@ impl SoundOutput { .control::, _>() .play(oddio::MonoToStereo::new(oddio::Gain::new( oddio::FramesSignal::from(samples), - 0.50, + 0.20, ))) } } diff --git a/src/state.rs b/src/state.rs index f866e9c..54d3ea5 100644 --- a/src/state.rs +++ b/src/state.rs @@ -117,7 +117,7 @@ impl State { let mut positions = self.ecs.write_storage::(); let mut players = self.ecs.write_storage::(); let monsters = self.ecs.write_storage::(); - let mut map = self.ecs.write_resource::(); + let map = self.ecs.read_resource::(); let mut stats = self.ecs.write_resource::(); let mut sound_system = self.ecs.write_resource::(); let wants_to_whips = self.ecs.read_storage::(); @@ -148,9 +148,6 @@ impl State { } } - let index = map.point2d_to_index(Point::from(*pos)); - map.clear_tile_content(index); - pos.x = destination.x; pos.y = destination.y; @@ -158,9 +155,6 @@ impl State { player_pos.x = pos.x; player_pos.y = pos.y; - let index = map.point2d_to_index(destination); - map.set_tile_content(index, player_entity); - self.ecs.write_resource::().force_tick(); sound_system.play_sound(sound_effects.step.clone()); @@ -178,37 +172,19 @@ impl State { pub fn draw_whip(&self, ctx: &mut BTerm) { let positions = self.ecs.read_storage::(); let wants_to_whips = self.ecs.read_storage::(); - let map = self.ecs.read_resource::(); let mut rng = RandomNumberGenerator::new(); for (position, wants_to_whip) in (&positions, &wants_to_whips).join() { let color = RGB::named(vga::get_by_index(rng.range(1, 16))); - let mut rendered_frame = wants_to_whip.frame; - let frame_data = loop { - let frame_data = match rendered_frame { - 0 => Some((-1, -1, '\\')), - 1 => Some((-1, 0, '─')), - 2 => Some((-1, 1, '/')), - 3 => Some((0, 1, '│')), - 4 => Some((1, 1, '\\')), - 5 => Some((1, 0, '─')), - 6 => Some((1, -1, '/')), - 7 => Some((0, -1, '│')), - _ => None, - }; - - if let Some(data) = frame_data { - let dest = Point { - x: position.x + data.0, - y: position.y + data.1, - }; - if map.in_bounds(dest) { - break frame_data; - } - rendered_frame += 1; - if rendered_frame > 7 { - break None; - } - } + let frame_data = match wants_to_whip.frame { + 0 => Some((-1, -1, '\\')), + 1 => Some((-1, 0, '─')), + 2 => Some((-1, 1, '/')), + 3 => Some((0, 1, '│')), + 4 => Some((1, 1, '\\')), + 5 => Some((1, 0, '─')), + 6 => Some((1, -1, '/')), + 7 => Some((0, -1, '│')), + _ => None, }; if let Some(data) = frame_data { ctx.set( @@ -223,6 +199,9 @@ impl State { } fn run_systems(&mut self) { + let mut map_indexing_system = MapIndexingSystem {}; + map_indexing_system.run_now(&self.ecs); + let mut whip_system = WhipSystem {}; whip_system.run_now(&self.ecs); diff --git a/src/systems/map_indexing_system.rs b/src/systems/map_indexing_system.rs new file mode 100644 index 0000000..1339cf9 --- /dev/null +++ b/src/systems/map_indexing_system.rs @@ -0,0 +1,27 @@ +use bracket_lib::prelude::*; +use specs::prelude::*; + +use crate::{components::Position, resources::Map}; + +pub struct MapIndexingSystem {} + +impl<'a> System<'a> for MapIndexingSystem { + type SystemData = ( + WriteExpect<'a, Map>, + ReadStorage<'a, Position>, + Entities<'a>, + ); + + fn run(&mut self, data: Self::SystemData) { + let (mut map, position, entities) = data; + + map.clear_all_tile_content(); + for (entity, position) in (&entities, &position).join() { + let index = map.point2d_to_index(Point { + x: position.x, + y: position.y, + }); + map.set_tile_content(index, entity); + } + } +} diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 2845938..477f4e3 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -1,5 +1,7 @@ +pub mod map_indexing_system; pub mod monster_ai_system; pub mod whip_system; +pub use map_indexing_system::MapIndexingSystem; pub use monster_ai_system::MonsterAiSystem; pub use whip_system::WhipSystem; diff --git a/src/systems/monster_ai_system.rs b/src/systems/monster_ai_system.rs index 91694f0..243aaeb 100644 --- a/src/systems/monster_ai_system.rs +++ b/src/systems/monster_ai_system.rs @@ -17,7 +17,7 @@ impl<'a> System<'a> for MonsterAiSystem { Entities<'a>, ReadExpect<'a, Clock>, ReadExpect<'a, Point>, - WriteExpect<'a, Map>, + ReadExpect<'a, Map>, WriteExpect<'a, Stats>, WriteStorage<'a, Monster>, WriteStorage<'a, Position>, @@ -31,7 +31,7 @@ impl<'a> System<'a> for MonsterAiSystem { entities, clock, player_pos, - mut map, + map, mut stats, mut monsters, mut positions, @@ -88,12 +88,8 @@ impl<'a> System<'a> for MonsterAiSystem { let _ = entities.delete(*entity); } _ => { - let index = map.point2d_to_index(Point::from(**position)); - map.clear_tile_content(index); position.x = destination.x; position.y = destination.y; - let index = map.point2d_to_index(destination); - map.set_tile_content(index, *entity); } } } diff --git a/src/systems/whip_system.rs b/src/systems/whip_system.rs index 911c583..d22c764 100644 --- a/src/systems/whip_system.rs +++ b/src/systems/whip_system.rs @@ -43,65 +43,50 @@ impl<'a> System<'a> for WhipSystem { stop_clock.0 = true; let now = Instant::now(); if now - wants_to_whip.last_frame > Duration::from_secs_f32(0.1) { - let destination = loop { - let destination = match wants_to_whip.frame { - 0 => Some(Point { - x: position.x - 1, - y: position.y - 1, - }), - 1 => Some(Point { - x: position.x - 1, - y: position.y, - }), - 2 => Some(Point { - x: position.x - 1, - y: position.y + 1, - }), - 3 => Some(Point { - x: position.x, - y: position.y + 1, - }), - 4 => Some(Point { - x: position.x + 1, - y: position.y + 1, - }), - 5 => Some(Point { - x: position.x + 1, - y: position.y, - }), - 6 => Some(Point { - x: position.x + 1, - y: position.y - 1, - }), - 7 => Some(Point { - x: position.x, - y: position.y - 1, - }), - _ => None, - }; - - if let Some(dest) = destination { - if map.in_bounds(dest) { - break destination; - } - wants_to_whip.frame += 1; - if wants_to_whip.frame > 7 { - break None; - } - } + let destination = match wants_to_whip.frame { + 0 => Some(Point { + x: position.x - 1, + y: position.y - 1, + }), + 1 => Some(Point { + x: position.x - 1, + y: position.y, + }), + 2 => Some(Point { + x: position.x - 1, + y: position.y + 1, + }), + 3 => Some(Point { + x: position.x, + y: position.y + 1, + }), + 4 => Some(Point { + x: position.x + 1, + y: position.y + 1, + }), + 5 => Some(Point { + x: position.x + 1, + y: position.y, + }), + 6 => Some(Point { + x: position.x + 1, + y: position.y - 1, + }), + 7 => Some(Point { + x: position.x, + y: position.y - 1, + }), + _ => None, }; if let Some(dest) = destination { - if let Some(e) = map.get_tile_content(map.point2d_to_index(dest)) { - if let Some(_monster) = monsters.get(e) { - let _ = entities.delete(e); - if let Some(sound) = &mut wants_to_whip.sound { - sound.control::, _>().stop(); - } - if wants_to_whip.frame == 7 { - wants_to_whip.sound = None; - sound_output.play_sound(sound_effects.whipping_hit_end.clone()); - } else { + if map.in_bounds(dest) { + if let Some(e) = map.get_tile_content(map.point2d_to_index(dest)) { + if let Some(_monster) = monsters.get(e) { + let _ = entities.delete(e); + if let Some(sound) = &mut wants_to_whip.sound { + sound.control::, _>().stop(); + } wants_to_whip.sound = Some( sound_output.play_sound(sound_effects.whipping_hit.clone()), ); @@ -111,7 +96,7 @@ impl<'a> System<'a> for WhipSystem { } if wants_to_whip.frame < 7 { - wants_to_whip.frame += 1; + (*wants_to_whip).frame += 1; wants_to_whip.last_frame = now; } else { entities_to_remove.push(entity);