You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
martian-chess/src/audio.rs

154 lines
5.4 KiB
Rust

///
/// TODO: Custom Asset: FmodEventMapper
///
use crate::prelude::*;
use bevy::prelude::*;
use bevy_fmod::prelude::AudioSource;
use bevy_fmod::prelude::*;
pub(crate) struct AudioPlugin;
impl Plugin for AudioPlugin {
fn build(&self, app: &mut App) {
app.add_event::<AudioEvent>();
app.add_plugins(FmodPlugin {
audio_banks_paths: &[
"./assets/audio/Martian Chess Audio/Build/Desktop/Master.bank",
"./assets/audio/Martian Chess Audio/Build/Desktop/Master.strings.bank",
"./assets/audio/Martian Chess Audio/Build/Desktop/Music.bank",
"./assets/audio/Martian Chess Audio/Build/Desktop/SFX.bank",
],
});
app.init_resource::<AudioVolume>();
app.add_systems(OnEnter(GameState::Intro), play_background);
app.add_systems(
Update,
(
play_audio.run_if(any_component_added::<AudioSource>),
audio_trigger.run_if(on_event::<AudioEvent>()),
control_volume.run_if(resource_changed::<AudioVolume>()),
toggle_volume
.run_if(|keys: Res<Input<KeyCode>>| -> bool { keys.just_pressed(KeyCode::M) }),
),
);
}
}
#[derive(Event, Debug, PartialEq, Component, Clone)]
pub enum AudioEvent {
MainMusic,
_StopMainMusic,
MenuHover,
MenuSelect,
PickUp,
PutDown,
Idle,
StopIdle,
Invalid,
}
#[derive(Resource, Debug)]
pub struct AudioVolume(f32);
impl Default for AudioVolume {
fn default() -> Self {
AudioVolume(1.0)
}
}
fn play_background(mut events: EventWriter<AudioEvent>) {
events.send(AudioEvent::MainMusic);
}
fn play_audio(mut events: Query<&AudioSource, Added<AudioSource>>) {
events.iter_mut().for_each(|aud| aud.play());
}
fn audio_trigger(
mut events: EventReader<AudioEvent>,
sources: Query<(Entity, &AudioSource, &AudioEvent)>,
studio: Res<FmodStudio>,
mut commands: Commands,
server: Res<AssetServer>,
tweaks: Res<Assets<tweak::Tweaks>>,
display_state: Res<State<DisplayState>>,
vol: Res<AudioVolume>,
) {
let tweak = tweaks
.get(&server.load("martian.tweak.toml"))
.expect("Load tweaks");
let state = display_state.get();
events.read().for_each(|event| {
let aud = match event {
AudioEvent::MainMusic | AudioEvent::_StopMainMusic => {
tweak.get::<String>("audio_music_main").unwrap()
}
AudioEvent::MenuHover => tweak.get::<String>("audio_menu_hover").unwrap(),
AudioEvent::MenuSelect => tweak.get::<String>("audio_menu_select").unwrap(),
AudioEvent::PickUp => tweak.get::<String>("audio_display3d_pick_up").unwrap(),
AudioEvent::PutDown => tweak.get::<String>("audio_display3d_put_down").unwrap(),
AudioEvent::Idle | AudioEvent::StopIdle => {
tweak.get::<String>("audio_display3d_idle").unwrap()
}
AudioEvent::Invalid => tweak.get::<String>("audio_display3d_invalid").unwrap(),
};
// There is an event, play an audio
if !aud.is_empty() {
let event_str = format!("event:{}", aud);
if let Ok(event_description) = studio.0.get_event(event_str.as_str()) {
// We are stopping a playing event
match event {
// Find and stop playing instances of idle audio
AudioEvent::StopIdle => {
sources
.iter()
.filter(|(_, _, source_event)| **source_event == AudioEvent::Idle)
.for_each(|(entity, source, _)| {
info!("Stopping audio {}", event_str);
source.stop();
commands.entity(entity).despawn_recursive();
});
}
// Find and stop playing instances of main music
AudioEvent::_StopMainMusic => {
sources
.iter()
.filter(|(_, _, source_event)| **source_event == AudioEvent::MainMusic)
.for_each(|(entity, source, _)| {
info!("Stopping audio {}", event_str);
source.stop();
commands.entity(entity).despawn_recursive();
});
}
// we are playing a sound
_ => {
info!("Playing audio {}", event_str);
let audio_source = AudioSource::new(event_description);
audio_source.set_volume(vol.0);
// TODO: Can we batch spawn all sounds at startup? Then Start/Stop/Reset at runtime?
commands.spawn((audio_source, event.clone()));
}
}
} else {
warn!("No music set for {:?} in {:?}", event, state);
}
}
});
}
fn toggle_volume(mut vol: ResMut<AudioVolume>) {
if vol.0 > 0.0 {
vol.0 = 0.0;
} else {
vol.0 = 1.0;
}
}
fn control_volume(vol: Res<AudioVolume>, query: Query<&AudioSource>) {
query
.iter()
.for_each(|aud_src| aud_src.set_volume((*vol).0));
}