Add pitch-shifting when behind.
This commit is contained in:
parent
0b9fd0921d
commit
7087e47e6a
|
@ -6,6 +6,7 @@ pub use bevy_input_actionmap;
|
||||||
pub use bevy_openal;
|
pub use bevy_openal;
|
||||||
pub use bevy_rapier2d;
|
pub use bevy_rapier2d;
|
||||||
pub use bevy_tts;
|
pub use bevy_tts;
|
||||||
|
pub mod commands;
|
||||||
pub use coord_2d;
|
pub use coord_2d;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod core;
|
pub mod core;
|
||||||
|
@ -19,6 +20,7 @@ pub mod map;
|
||||||
pub use mapgen;
|
pub use mapgen;
|
||||||
pub mod navigation;
|
pub mod navigation;
|
||||||
pub mod pathfinding;
|
pub mod pathfinding;
|
||||||
|
pub mod pitch_shift;
|
||||||
pub use rand;
|
pub use rand;
|
||||||
pub use shadowcast;
|
pub use shadowcast;
|
||||||
pub mod sound;
|
pub mod sound;
|
||||||
|
|
172
src/pitch_shift.rs
Normal file
172
src/pitch_shift.rs
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bevy_openal::{Listener, Sound},
|
||||||
|
commands::RunIfExistsExt,
|
||||||
|
derive_more::{Deref, DerefMut},
|
||||||
|
sound::SoundIcon,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Component, Clone, Copy, Debug, Default)]
|
||||||
|
struct Behind;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct PitchShiftConfig {
|
||||||
|
pub downshift_behind: bool,
|
||||||
|
pub downshift: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PitchShiftConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
downshift_behind: false,
|
||||||
|
downshift: 0.95,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag_behind(
|
||||||
|
mut commands: Commands,
|
||||||
|
config: Res<PitchShiftConfig>,
|
||||||
|
sounds: Query<(Entity, &GlobalTransform, Option<&Sound>, Option<&SoundIcon>)>,
|
||||||
|
listener: Query<&GlobalTransform, With<Listener>>,
|
||||||
|
behind: Query<Entity, With<Behind>>,
|
||||||
|
) {
|
||||||
|
if config.downshift_behind {
|
||||||
|
if let Ok(listener_transform) = listener.get_single() {
|
||||||
|
let listener_forward = listener_transform.local_x();
|
||||||
|
for (entity, transform, sound, icon) in sounds.iter() {
|
||||||
|
if icon.is_none() && sound.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let v = transform.translation - listener_transform.translation;
|
||||||
|
let dot = v.dot(listener_forward);
|
||||||
|
let is_behind = dot <= 0.;
|
||||||
|
if is_behind {
|
||||||
|
commands.run_if_exists(entity, |mut entity| {
|
||||||
|
entity.insert(Behind);
|
||||||
|
});
|
||||||
|
} else if !is_behind {
|
||||||
|
commands.run_if_exists(entity, |mut entity| {
|
||||||
|
entity.remove::<Behind>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for entity in behind.iter() {
|
||||||
|
commands.run_if_exists(entity, |mut entity| {
|
||||||
|
entity.remove::<Behind>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deref, DerefMut)]
|
||||||
|
struct LastIconPitch(HashMap<Entity, f32>);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deref, DerefMut)]
|
||||||
|
struct LastSoundPitch(HashMap<Entity, f32>);
|
||||||
|
|
||||||
|
fn behind_added(
|
||||||
|
config: Res<PitchShiftConfig>,
|
||||||
|
mut last_icon_pitch: ResMut<LastIconPitch>,
|
||||||
|
mut last_sound_pitch: ResMut<LastSoundPitch>,
|
||||||
|
mut query: Query<(Entity, Option<&mut SoundIcon>, Option<&mut Sound>), Added<Behind>>,
|
||||||
|
) {
|
||||||
|
for (entity, icon, sound) in query.iter_mut() {
|
||||||
|
if let Some(mut icon) = icon {
|
||||||
|
icon.pitch *= config.downshift;
|
||||||
|
last_icon_pitch.insert(entity, icon.pitch);
|
||||||
|
} else if let Some(mut sound) = sound {
|
||||||
|
sound.pitch *= config.downshift;
|
||||||
|
last_sound_pitch.insert(entity, sound.pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn behind_removed(
|
||||||
|
config: Res<PitchShiftConfig>,
|
||||||
|
mut last_icon_pitch: ResMut<LastIconPitch>,
|
||||||
|
mut last_sound_pitch: ResMut<LastSoundPitch>,
|
||||||
|
removed: RemovedComponents<Behind>,
|
||||||
|
mut icons: Query<&mut SoundIcon>,
|
||||||
|
mut sounds: Query<&mut Sound>,
|
||||||
|
) {
|
||||||
|
let downshift = 1. / config.downshift;
|
||||||
|
for entity in removed.iter() {
|
||||||
|
if let Ok(mut icon) = icons.get_mut(entity) {
|
||||||
|
icon.pitch *= downshift;
|
||||||
|
last_icon_pitch.remove(&entity);
|
||||||
|
} else if let Ok(mut sound) = sounds.get_mut(entity) {
|
||||||
|
sound.pitch *= downshift;
|
||||||
|
last_sound_pitch.remove(&entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sound_icon_changed(
|
||||||
|
config: Res<PitchShiftConfig>,
|
||||||
|
mut last_icon_pitch: ResMut<LastIconPitch>,
|
||||||
|
mut icons: Query<(Entity, &mut SoundIcon), (With<Behind>, Changed<SoundIcon>)>,
|
||||||
|
) {
|
||||||
|
for (entity, mut icon) in icons.iter_mut() {
|
||||||
|
let should_change = if let Some(pitch) = last_icon_pitch.get(&entity) {
|
||||||
|
*pitch != icon.pitch
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if should_change {
|
||||||
|
icon.pitch *= config.downshift;
|
||||||
|
last_icon_pitch.insert(entity, icon.pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sound_changed(
|
||||||
|
config: Res<PitchShiftConfig>,
|
||||||
|
mut last_sound_pitch: ResMut<LastSoundPitch>,
|
||||||
|
mut sounds: Query<(Entity, &mut Sound), (With<Behind>, Without<SoundIcon>, Changed<Sound>)>,
|
||||||
|
) {
|
||||||
|
for (entity, mut sound) in sounds.iter_mut() {
|
||||||
|
let should_change = if let Some(pitch) = last_sound_pitch.get(&entity) {
|
||||||
|
*pitch != sound.pitch
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if should_change {
|
||||||
|
sound.pitch *= config.downshift;
|
||||||
|
last_sound_pitch.insert(entity, sound.pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_config(
|
||||||
|
mut commands: Commands,
|
||||||
|
config: Res<PitchShiftConfig>,
|
||||||
|
behind: Query<Entity, With<Behind>>,
|
||||||
|
) {
|
||||||
|
if config.is_changed() {
|
||||||
|
for entity in behind.iter() {
|
||||||
|
commands.entity(entity).remove::<Behind>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PitchShiftPlugin;
|
||||||
|
|
||||||
|
impl Plugin for PitchShiftPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.init_resource::<PitchShiftConfig>()
|
||||||
|
.init_resource::<LastIconPitch>()
|
||||||
|
.init_resource::<LastSoundPitch>()
|
||||||
|
.add_system_to_stage(CoreStage::PreUpdate, tag_behind)
|
||||||
|
.add_system(behind_added)
|
||||||
|
.add_system_to_stage(CoreStage::PostUpdate, behind_removed)
|
||||||
|
.add_system(sound_icon_changed)
|
||||||
|
.add_system(sound_changed)
|
||||||
|
.add_system(sync_config);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user