181 lines
5.1 KiB
Rust
181 lines
5.1 KiB
Rust
use bevy::prelude::*;
|
|
use bevy_synthizer::{Audio, Sound};
|
|
|
|
use rand::random;
|
|
|
|
use crate::{
|
|
core::Player,
|
|
exploration::ExplorationFocused,
|
|
visibility::{Visible, VisibleEntities},
|
|
};
|
|
|
|
#[derive(Component, Clone, Debug)]
|
|
pub struct SoundIcon {
|
|
pub audio: Audio,
|
|
pub gain: f64,
|
|
pub pitch: f64,
|
|
pub interval: Option<Timer>,
|
|
}
|
|
|
|
impl Default for SoundIcon {
|
|
fn default() -> Self {
|
|
let seconds = random::<f32>() + 4.5;
|
|
Self {
|
|
audio: default(),
|
|
gain: 1.,
|
|
pitch: 1.,
|
|
interval: Some(Timer::from_seconds(seconds, TimerMode::Once)),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn added(mut commands: Commands, icons: Query<(Entity, &SoundIcon), Added<SoundIcon>>) {
|
|
for (entity, icon) in &icons {
|
|
let buffer = icon.audio.clone();
|
|
let gain = icon.gain;
|
|
let pitch = icon.pitch;
|
|
let looping = icon.interval.is_none();
|
|
commands.entity(entity).insert(Sound {
|
|
audio: buffer,
|
|
gain,
|
|
pitch,
|
|
looping,
|
|
paused: true,
|
|
..default()
|
|
});
|
|
}
|
|
}
|
|
|
|
fn update<S>(
|
|
config: Res<SoundIconPlugin<S>>,
|
|
state: Res<State<S>>,
|
|
time: Res<Time>,
|
|
viewers: Query<&VisibleEntities, With<Player>>,
|
|
mut icons: Query<(
|
|
Entity,
|
|
&mut SoundIcon,
|
|
Option<&Visible>,
|
|
Option<&Parent>,
|
|
&mut Sound,
|
|
)>,
|
|
) where
|
|
S: States,
|
|
{
|
|
if !config.states.is_empty() && !config.states.contains(state.get()) {
|
|
return;
|
|
}
|
|
for visible in &viewers {
|
|
for (icon_entity, mut icon, visibility, parent, mut sound) in &mut icons {
|
|
let entity = if visibility.is_some() {
|
|
Some(icon_entity)
|
|
} else if parent.is_some() {
|
|
Some(**parent.unwrap())
|
|
} else {
|
|
None
|
|
};
|
|
if let Some(entity) = entity {
|
|
if visible.contains(&entity) {
|
|
if let Some(interval) = icon.interval.as_mut() {
|
|
if interval.finished() {
|
|
interval.reset();
|
|
continue;
|
|
} else if interval.percent() == 0. {
|
|
sound.generator = None;
|
|
}
|
|
interval.tick(time.delta());
|
|
}
|
|
if sound.audio != icon.audio {
|
|
sound.audio = icon.audio.clone();
|
|
}
|
|
if sound.gain != icon.gain {
|
|
sound.gain = icon.gain;
|
|
}
|
|
if sound.pitch != icon.pitch {
|
|
sound.pitch = icon.pitch;
|
|
}
|
|
let looping = icon.interval.is_none();
|
|
if sound.looping != looping {
|
|
sound.looping = looping;
|
|
}
|
|
if sound.paused {
|
|
sound.paused = false;
|
|
sound.generator = None;
|
|
}
|
|
} else if !sound.paused {
|
|
sound.paused = true;
|
|
if let Some(interval) = icon.interval.as_mut() {
|
|
interval.reset();
|
|
}
|
|
}
|
|
} else {
|
|
panic!("Should not happen");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn exploration_focus_changed(
|
|
mut focused: Query<(Entity, Option<&Children>), Changed<ExplorationFocused>>,
|
|
mut icons: Query<&mut SoundIcon>,
|
|
) {
|
|
const ICON_GAIN: f64 = 3.;
|
|
for (entity, children) in &mut focused {
|
|
if let Ok(mut icon) = icons.get_mut(entity) {
|
|
icon.gain *= ICON_GAIN;
|
|
}
|
|
if let Some(children) = children {
|
|
for child in children.iter() {
|
|
if let Ok(mut icon) = icons.get_mut(*child) {
|
|
icon.gain *= ICON_GAIN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn exploration_focus_removed(
|
|
mut removed: RemovedComponents<ExplorationFocused>,
|
|
mut query: Query<&mut SoundIcon>,
|
|
children: Query<&Children>,
|
|
) {
|
|
const ICON_GAIN: f64 = 3.;
|
|
for entity in &mut removed {
|
|
if let Ok(mut icon) = query.get_mut(entity) {
|
|
icon.gain /= ICON_GAIN;
|
|
}
|
|
if let Ok(children) = children.get(entity) {
|
|
for child in children.iter() {
|
|
if let Ok(mut icon) = query.get_mut(*child) {
|
|
icon.gain /= ICON_GAIN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Resource, Clone)]
|
|
pub struct SoundIconPlugin<S> {
|
|
pub states: Vec<S>,
|
|
}
|
|
|
|
impl<S> Default for SoundIconPlugin<S> {
|
|
fn default() -> Self {
|
|
Self { states: default() }
|
|
}
|
|
}
|
|
|
|
impl<S> Plugin for SoundIconPlugin<S>
|
|
where
|
|
S: States,
|
|
{
|
|
fn build(&self, app: &mut App) {
|
|
app.insert_resource(self.clone())
|
|
.add_systems(PreUpdate, added)
|
|
.add_systems(PreUpdate, (exploration_focus_changed, update::<S>).chain())
|
|
.add_systems(
|
|
PostUpdate,
|
|
exploration_focus_removed.after(exploration_focus_changed),
|
|
);
|
|
}
|
|
}
|