From fea57af6d196d8d6879549811cb7d48fa7a257ea Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sun, 5 Jan 2025 20:47:12 +0200 Subject: [PATCH] feat(vfx): add movement sound --- src/lib.rs | 2 +- src/player/assets.rs | 29 ++++++++++++++++++++++++++++ src/player/mod.rs | 4 ++++ src/player/systems/mod.rs | 8 ++++++++ src/player/systems/sound_effect.rs | 31 ++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/player/systems/sound_effect.rs diff --git a/src/lib.rs b/src/lib.rs index bdb1c52..9ad5598 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,7 @@ impl Plugin for AppPlugin { }) .set(AudioPlugin { global_volume: GlobalVolume { - volume: Volume::new(0.3), + volume: Volume::new(0.2), }, ..default() }), diff --git a/src/player/assets.rs b/src/player/assets.rs index 0f8345a..4de7e08 100644 --- a/src/player/assets.rs +++ b/src/player/assets.rs @@ -17,3 +17,32 @@ pub(super) fn blue_material() -> StandardMaterial { ..default() } } + +#[derive(Resource, Asset, Reflect, Clone)] +pub struct PlayerAssets { + // This #[dependency] attribute marks the field as a dependency of the Asset. + // This means that it will not finish loading until the labeled asset is also loaded. + #[dependency] + pub steps: Vec>, +} + +impl PlayerAssets { + pub const PATH_STEP_1: &str = "audio/sound_effects/step1.ogg"; + pub const PATH_STEP_2: &str = "audio/sound_effects/step2.ogg"; + pub const PATH_STEP_3: &str = "audio/sound_effects/step3.ogg"; + pub const PATH_STEP_4: &str = "audio/sound_effects/step4.ogg"; +} + +impl FromWorld for PlayerAssets { + fn from_world(world: &mut World) -> Self { + let assets = world.resource::(); + Self { + steps: vec![ + assets.load(Self::PATH_STEP_1), + assets.load(Self::PATH_STEP_2), + assets.load(Self::PATH_STEP_3), + assets.load(Self::PATH_STEP_4), + ], + } + } +} diff --git a/src/player/mod.rs b/src/player/mod.rs index 480168d..6414c08 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -4,12 +4,16 @@ pub mod events; mod systems; mod triggers; +use assets::PlayerAssets; use bevy::{ecs::system::RunSystemOnce, prelude::*}; use components::Player; use events::{DespawnPlayer, RespawnPlayer, SpawnPlayer}; +use crate::asset_tracking::LoadResource; + pub(super) fn plugin(app: &mut App) { app.register_type::() + .load_resource::() .add_event::() .add_event::() .add_event::() diff --git a/src/player/systems/mod.rs b/src/player/systems/mod.rs index 080d5f2..ae65cb4 100644 --- a/src/player/systems/mod.rs +++ b/src/player/systems/mod.rs @@ -1,14 +1,18 @@ mod input; mod movement; pub mod setup; +mod sound_effect; mod vertical_transition; use crate::{screens::Screen, AppSet}; use bevy::prelude::*; use input::player_input; use movement::player_movement; +use sound_effect::play_movement_sound; use vertical_transition::handle_floor_transition; +use super::assets::PlayerAssets; + pub(super) fn plugin(app: &mut App) { app.add_systems( Update, @@ -16,6 +20,10 @@ pub(super) fn plugin(app: &mut App) { player_input.in_set(AppSet::RecordInput), player_movement, handle_floor_transition.in_set(AppSet::RecordInput), + (play_movement_sound) + .chain() + .run_if(resource_exists::) + .in_set(AppSet::Update), ) .chain() .run_if(in_state(Screen::Gameplay)), diff --git a/src/player/systems/sound_effect.rs b/src/player/systems/sound_effect.rs new file mode 100644 index 0000000..0972660 --- /dev/null +++ b/src/player/systems/sound_effect.rs @@ -0,0 +1,31 @@ +use crate::{ + audio::SoundEffect, + player::{ + assets::PlayerAssets, + components::{MovementTarget, Player}, + }, +}; + +use bevy::prelude::*; +use rand::seq::SliceRandom; + +pub fn play_movement_sound( + mut commands: Commands, + player_assets: Res, + moving_players: Query<&MovementTarget, (Changed, With)>, +) { + for movement_target in moving_players.iter() { + if movement_target.is_none() { + continue; + } + + let rng = &mut rand::thread_rng(); + if let Some(random_step) = player_assets.steps.choose(rng) { + commands.spawn(( + AudioPlayer(random_step.clone()), + PlaybackSettings::DESPAWN, + SoundEffect, + )); + } + } +}