diff options
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | assets/asm/placeholder.asm | 7 | ||||
| -rw-r--r-- | audio/src/channel.rs | 5 | ||||
| -rw-r--r-- | audio/src/data.rs | 46 | ||||
| -rw-r--r-- | audio/src/lib.rs | 12 | ||||
| -rw-r--r-- | audio/src/program.rs | 17 | ||||
| -rw-r--r-- | game/Cargo.toml | 1 | ||||
| -rw-r--r-- | game/src/lib.rs | 64 | ||||
| -rw-r--r-- | game/src/main.rs | 4 | ||||
| -rw-r--r-- | game/src/music.rs | 74 |
10 files changed, 155 insertions, 76 deletions
@@ -185,6 +185,7 @@ name = "game" version = "0.1.0" dependencies = [ "argh", + "audio", "dungeon", "graphics", ] diff --git a/assets/asm/placeholder.asm b/assets/asm/placeholder.asm new file mode 100644 index 0000000..6e4e060 --- /dev/null +++ b/assets/asm/placeholder.asm @@ -0,0 +1,7 @@ +; note this file does not play anything! +; its just a placeholder for not yet +; created audio + +; single pause to not +; cause infinite loop +- diff --git a/audio/src/channel.rs b/audio/src/channel.rs index 48d416b..b74792e 100644 --- a/audio/src/channel.rs +++ b/audio/src/channel.rs @@ -149,6 +149,11 @@ impl Channels { } } } +impl Default for Channels { + fn default() -> Self { + Self::new() + } +} pub struct Device<'s> { pub channels: Arc<Atomic<Channels>>, diff --git a/audio/src/data.rs b/audio/src/data.rs deleted file mode 100644 index 934e186..0000000 --- a/audio/src/data.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::program::Track; -use std::fs; - -macro_rules! load_asm { - ($path:tt) => {{ - let res = if cfg!(any(feature = "static", target_arch = "wasm32")) { - let src = include_str!(concat!("../../", $path)); - Track::parse(src) - } else { - let src = fs::read_to_string($path)?; - Track::parse(&src) - }; - res.map_err(|mut err| { - err.file = Some(String::from($path)); - err - })? - }}; - ($first:tt, $($arg:tt),*) => { - load_asm!($first)$(.merge(load_asm!($arg)))* - }; -} - -pub struct Data { - pub explore: Track, - pub megalovania: Track, - pub test: Track, -} -impl Data { - pub fn load() -> crate::Result<Self> { - let explore = load_asm!( - "assets/asm/explore_melody.asm", - "assets/asm/explore_harmony1.asm", - "assets/asm/explore_harmony2.asm" - ); - let megalovania = load_asm!( - "assets/asm/megalovania_melody.asm", - "assets/asm/megalovania_base.asm" - ); - let test = load_asm!("assets/asm/test.asm"); - Ok(Self { - explore, - megalovania, - test, - }) - } -} diff --git a/audio/src/lib.rs b/audio/src/lib.rs index 814bcd0..8158c35 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -3,12 +3,12 @@ use raylib::audio::RaylibAudio; use std::{ collections::BinaryHeap, + rc::Rc, sync::atomic::Ordering, time::{Duration, Instant}, }; use channel::Device; -use data::Data; use crate::{ channel::Channels, @@ -16,9 +16,8 @@ use crate::{ }; mod channel; -mod data; mod parse; -mod program; +pub mod program; /// The `Error` type used within this crate pub type Error = Box<dyn std::error::Error>; @@ -36,7 +35,6 @@ pub struct Audio { device: Device<'static>, last: Instant, queue: BinaryHeap<Program>, - pub data: Data, } impl Audio { pub fn load() -> crate::Result<Self> { @@ -53,17 +51,15 @@ impl Audio { let device = Device::load(handle)?; let last = Instant::now(); let queue = BinaryHeap::new(); - let data = Data::load()?; Ok(Self { device, last, queue, - data, }) } - pub fn schedule(&mut self, track: Track, priority: u32, looping: bool) { + pub fn schedule(&mut self, track: Rc<Track>, priority: u32, looping: bool) { let program = Program::new(track, priority, looping); self.queue.push(program); } @@ -86,7 +82,7 @@ impl Audio { res } // make the output quiet! - None => Channels::new(), + None => Channels::default(), }; self.device.channels.store(channels, Ordering::Relaxed); self.last = Instant::now(); diff --git a/audio/src/program.rs b/audio/src/program.rs index b775e24..cd050e3 100644 --- a/audio/src/program.rs +++ b/audio/src/program.rs @@ -52,22 +52,23 @@ use Instruction as I; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Track { - pub ins: Rc<Vec<Instruction>>, + pub ins: Vec<Instruction>, } impl Track { pub fn parse(src: &str) -> parse::Result<Self> { - let ins = Rc::new(parse::parse(src)?); + let ins = parse::parse(src)?; Ok(Self { ins }) } - pub fn merge(self, other: Self) -> Self { + #[must_use] + pub fn merge(&self, other: &Self) -> Self { let mut res = vec![]; let mut l = 0; let mut r = 0; let mut l_pause = 0; let mut r_pause = 0; - let l_ins = self.ins; - let r_ins = other.ins; + let l_ins = &self.ins; + let r_ins = &other.ins; loop { if l >= l_ins.len() && r >= r_ins.len() { @@ -124,7 +125,7 @@ impl Track { } } - Self { ins: Rc::new(res) } + Self { ins: res } } } impl fmt::Display for Track { @@ -141,7 +142,7 @@ impl fmt::Display for Track { #[derive(Debug, Clone, PartialEq, Eq)] pub struct Program { - track: Track, + track: Rc<Track>, priority: u32, looping: bool, pc: usize, @@ -150,7 +151,7 @@ pub struct Program { channels: Channels, } impl Program { - pub const fn new(track: Track, priority: u32, looping: bool) -> Self { + pub const fn new(track: Rc<Track>, priority: u32, looping: bool) -> Self { Self { track, priority, diff --git a/game/Cargo.toml b/game/Cargo.toml index 5cdf4af..3371f50 100644 --- a/game/Cargo.toml +++ b/game/Cargo.toml @@ -8,6 +8,7 @@ publish.workspace = true rust-version.workspace = true [dependencies] +audio.workspace = true argh.workspace = true dungeon.workspace = true graphics.workspace = true diff --git a/game/src/lib.rs b/game/src/lib.rs index 436d488..6e09a37 100644 --- a/game/src/lib.rs +++ b/game/src/lib.rs @@ -1,28 +1,53 @@ +use std::rc::Rc; + use dungeon::{ Dungeon, UpdateResult, entity::Item, map::Tile, player::PLAYER_INVENTORY_SIZE_USIZE, player_input::PlayerInput, pos::Direction, }; use graphics::{Key, Window}; +use crate::music::Music; + +mod music; + +macro_rules! play_sound { + ($self:expr, $sound:expr) => { + $self.window.audio().schedule( + Rc::clone(&$sound.track), + $sound.priority, + $sound.looping, + ); + }; +} + +/// The `Error` type used within this crate +pub type Error = Box<dyn std::error::Error>; + +/// The `Result` type used witin this crate +pub type Result<T> = std::result::Result<T, crate::Error>; + pub struct Game { window: Window, dungeon: Dungeon, + music: Music, // to ensure the most recently-pressed direction key is used: current_dir: Option<(Direction, Key)>, } impl Game { - pub fn new(window: Window, seed: Option<u64>) -> Self { + pub fn new(window: Window, seed: Option<u64>) -> Result<Self> { + let music = Music::load()?; let dungeon = match seed { Some(s) => Dungeon::new(s), None => Dungeon::random(), }; - - Self { + let game = Self { window, dungeon, + music, current_dir: None, - } + }; + Ok(game) } fn player_dir(&mut self) -> Option<Direction> { @@ -79,9 +104,7 @@ impl Game { } pub fn run(&mut self) { - //// debug music - //let track = self.window.audio().data.test.clone(); - //self.window.audio().schedule(track, 1, true); + play_sound!(self, &self.music.background); // Main game loop while self.window.is_open() { @@ -100,19 +123,36 @@ impl Game { .dungeon .update(inputs, self.window.delta_time().as_secs_f32()); match result { - UpdateResult::Default(_action) => { - // TODO: make noises for player actions + UpdateResult::Default(action) => { + // items + if action.bomb { + play_sound!(self, &self.music.use_bomb); + } else if action.potion { + play_sound!(self, &self.music.use_potion); + } else if action.drop_item { + play_sound!(self, &self.music.drop_item); + } else if action.pickup_item { + play_sound!(self, &self.music.pickup_item); + } + + // actions + if action.attack { + play_sound!(self, &self.music.attack); + } else if action.walk { + // TODO: do we want walking sounds? (were a ghost) + } } UpdateResult::NextFloor => { - // TODO: stairs audio + play_sound!(self, &self.music.discover); } UpdateResult::MessageUpdated(changed) => { if changed { - //self.window.audio().speak.play(); + play_sound!(self, &self.music.speak); } } UpdateResult::GameOver => { - // TODO: player game over music, very sad + self.window.audio().clear(); + play_sound!(self, &self.music.game_over); } UpdateResult::Nothing => {} } diff --git a/game/src/main.rs b/game/src/main.rs index cf82239..353c521 100644 --- a/game/src/main.rs +++ b/game/src/main.rs @@ -16,7 +16,7 @@ struct Args { seed: Option<u64>, } -fn run() -> graphics::Result<()> { +fn run() -> game::Result<()> { // Parse arguments let args: Args = argh::from_env(); // Load the window @@ -24,7 +24,7 @@ fn run() -> graphics::Result<()> { .vsync(args.vsync) .verbose(args.verbose) .build()?; - Game::new(window, args.seed).run(); + Game::new(window, args.seed)?.run(); Ok(()) } diff --git a/game/src/music.rs b/game/src/music.rs new file mode 100644 index 0000000..366e79d --- /dev/null +++ b/game/src/music.rs @@ -0,0 +1,74 @@ +use audio::program::Track; +use std::{fs, rc::Rc}; + +macro_rules! load_asm { + ($path:tt) => {{ + let res = if cfg!(any(feature = "static", target_arch = "wasm32")) { + let src = include_str!(concat!("../../", $path)); + Track::parse(src) + } else { + let src = fs::read_to_string($path)?; + Track::parse(&src) + }; + res.map_err(|mut err| { + err.file = Some(String::from($path)); + err + })? + }}; + ($first:tt, $($arg:tt),*) => { + load_asm!($first)$(.merge(&load_asm!($arg)))* + }; +} + +pub struct Sound { + pub track: Rc<Track>, + pub looping: bool, + pub priority: u32, +} +impl Sound { + fn new(track: Track, looping: bool, priority: u32) -> Self { + Self { + track: Rc::new(track), + looping, + priority, + } + } +} + +pub struct Music { + pub attack: Sound, + pub discover: Sound, + pub background: Sound, + pub game_over: Sound, + pub speak: Sound, + pub use_potion: Sound, + pub use_bomb: Sound, + pub drop_item: Sound, + pub pickup_item: Sound, +} +impl Music { + pub fn load() -> crate::Result<Self> { + // TODO: create REAL audio files + let attack = load_asm!("assets/asm/placeholder.asm"); + let discover = load_asm!("assets/asm/placeholder.asm"); + let background = load_asm!("assets/asm/placeholder.asm"); + let game_over = load_asm!("assets/asm/placeholder.asm"); + let speak = load_asm!("assets/asm/placeholder.asm"); + let use_potion = load_asm!("assets/asm/placeholder.asm"); + let use_bomb = load_asm!("assets/asm/placeholder.asm"); + let drop_item = load_asm!("assets/asm/placeholder.asm"); + let pickup_item = load_asm!("assets/asm/placeholder.asm"); + + Ok(Self { + attack: Sound::new(attack, false, 2), + discover: Sound::new(discover, false, 3), + background: Sound::new(background, true, 1), + game_over: Sound::new(game_over, true, 1), + speak: Sound::new(speak, false, 2), + use_potion: Sound::new(use_potion, false, 2), + use_bomb: Sound::new(use_bomb, false, 2), + drop_item: Sound::new(drop_item, false, 2), + pickup_item: Sound::new(pickup_item, false, 2), + }) + } +} |