diff --git a/src/sound/footstep.rs b/src/sound/footstep.rs new file mode 100644 index 0000000..a372771 --- /dev/null +++ b/src/sound/footstep.rs @@ -0,0 +1,103 @@ +use std::collections::HashMap; + +use bevy::{asset::HandleId, prelude::*, transform::TransformSystem}; +use bevy_openal::{Buffer, Sound, SoundState}; +use rand::random; + +use crate::{commands::RunIfExistsExt, core::PointLike}; + +#[derive(Component, Clone, Debug, Reflect)] +#[reflect(Component)] +pub struct Footstep { + pub sound: HandleId, + pub step_length: f32, + pub gain: f32, + pub reference_distance: f32, + pub max_distance: f32, + pub rolloff_factor: f32, + pub pitch: f32, + pub pitch_variation: Option, +} + +impl Default for Footstep { + fn default() -> Self { + Self { + sound: "".into(), + step_length: 0.8, + gain: 1., + reference_distance: 1., + max_distance: f32::MAX, + rolloff_factor: 1., + pitch: 1., + pitch_variation: Some(0.15), + } + } +} + +#[derive(Bundle, Default)] +pub struct FootstepBundle { + pub footstep: Footstep, + pub transform: Transform, + pub global_transform: GlobalTransform, +} + +fn added( + mut commands: Commands, + footsteps: Query<(Entity, &Footstep), Added>, + assets: Res>, +) { + for (entity, footstep) in footsteps.iter() { + let buffer = assets.get_handle(footstep.sound); + commands.run_if_exists(entity, move |mut entity| { + entity.insert(Sound { + buffer, + state: SoundState::Stopped, + ..default() + }); + }); + } +} + +fn update( + mut last_step_distance: Local>, + mut footsteps: Query<(Entity, &Footstep, &Parent, &mut Sound), Changed>, + transforms_storage: Query<&Transform>, +) { + for (entity, footstep, parent, mut sound) in footsteps.iter_mut() { + let coordinates = transforms_storage.get(**parent).unwrap(); + if let Some(last) = last_step_distance.get(&entity) { + let distance = last.0 + (last.1.distance(coordinates)); + if distance >= footstep.step_length { + last_step_distance.insert(entity, (0., *coordinates)); + sound.gain = footstep.gain; + sound.reference_distance = footstep.reference_distance; + sound.max_distance = footstep.max_distance; + sound.rolloff_factor = footstep.rolloff_factor; + sound.pitch = footstep.pitch; + if let Some(pitch_variation) = footstep.pitch_variation { + let mut pitch = footstep.pitch - pitch_variation / 2.; + pitch += random::() * pitch_variation; + sound.pitch = pitch; + } + sound.play(); + } else if last.1 != *coordinates { + last_step_distance.insert(entity, (distance, *coordinates)); + } + } else { + last_step_distance.insert(entity, (0., *coordinates)); + } + } +} + +pub struct FootstepPlugin; + +impl Plugin for FootstepPlugin { + fn build(&self, app: &mut App) { + app.register_type::() + .add_system(added) + .add_system_to_stage( + CoreStage::PostUpdate, + update.after(TransformSystem::TransformPropagate), + ); + } +} diff --git a/src/sound.rs b/src/sound/icon.rs similarity index 52% rename from src/sound.rs rename to src/sound/icon.rs index 0b2fb4a..52da287 100644 --- a/src/sound.rs +++ b/src/sound/icon.rs @@ -1,45 +1,17 @@ -use std::{collections::HashMap, fmt::Debug, hash::Hash, time::Duration}; +use std::{fmt::Debug, hash::Hash, time::Duration}; use bevy::{asset::HandleId, prelude::*, transform::TransformSystem}; -use bevy_openal::{Buffer, Context, Sound, SoundState}; +use bevy_openal::{Buffer, Sound, SoundState}; use rand::random; use crate::{ commands::RunIfExistsExt, - core::{CoreConfig, Player, PointLike}, + core::Player, exploration::ExplorationFocused, visibility::{Visible, VisibleEntities}, }; -#[derive(Component, Clone, Debug, Reflect)] -#[reflect(Component)] -pub struct Footstep { - pub sound: HandleId, - pub step_length: f32, - pub gain: f32, - pub reference_distance: f32, - pub max_distance: f32, - pub rolloff_factor: f32, - pub pitch: f32, - pub pitch_variation: Option, -} - -impl Default for Footstep { - fn default() -> Self { - Self { - sound: "".into(), - step_length: 0.8, - gain: 1., - reference_distance: 1., - max_distance: f32::MAX, - rolloff_factor: 1., - pitch: 1., - pitch_variation: Some(0.15), - } - } -} - #[derive(Component, Clone, Debug)] pub struct SoundIcon { pub sound: HandleId, @@ -71,13 +43,6 @@ impl Default for SoundIcon { } } -#[derive(Bundle, Default)] -pub struct FootstepBundle { - pub footstep: Footstep, - pub transform: Transform, - pub global_transform: GlobalTransform, -} - #[derive(Bundle, Clone, Debug, Default)] pub struct SoundIconBundle { pub sound_icon: SoundIcon, @@ -85,54 +50,6 @@ pub struct SoundIconBundle { pub global_transform: GlobalTransform, } -fn add_footstep_sounds( - mut commands: Commands, - footsteps: Query<(Entity, &Footstep), Added>, - assets: Res>, -) { - for (entity, footstep) in footsteps.iter() { - let buffer = assets.get_handle(footstep.sound); - commands.run_if_exists(entity, move |mut entity| { - entity.insert(Sound { - buffer, - state: SoundState::Stopped, - ..default() - }); - }); - } -} - -fn footstep( - mut last_step_distance: Local>, - mut footsteps: Query<(Entity, &Footstep, &Parent, &mut Sound), Changed>, - transforms_storage: Query<&Transform>, -) { - for (entity, footstep, parent, mut sound) in footsteps.iter_mut() { - let coordinates = transforms_storage.get(**parent).unwrap(); - if let Some(last) = last_step_distance.get(&entity) { - let distance = last.0 + (last.1.distance(coordinates)); - if distance >= footstep.step_length { - last_step_distance.insert(entity, (0., *coordinates)); - sound.gain = footstep.gain; - sound.reference_distance = footstep.reference_distance; - sound.max_distance = footstep.max_distance; - sound.rolloff_factor = footstep.rolloff_factor; - sound.pitch = footstep.pitch; - if let Some(pitch_variation) = footstep.pitch_variation { - let mut pitch = footstep.pitch - pitch_variation / 2.; - pitch += random::() * pitch_variation; - sound.pitch = pitch; - } - sound.play(); - } else if last.1 != *coordinates { - last_step_distance.insert(entity, (distance, *coordinates)); - } - } else { - last_step_distance.insert(entity, (0., *coordinates)); - } - } -} - fn add_sound_icon_sounds( mut commands: Commands, icons: Query<(Entity, &SoundIcon), Added>, @@ -162,8 +79,8 @@ fn add_sound_icon_sounds( } } -fn sound_icon( - config: Res>, +fn update( + config: Res>, state: Res>, time: Res