use bevy::prelude::*; use bevy::audio::PlaybackMode; use crate::settings; const ASSET_CLICK: &str = "sounds/click-button-140881-crop.ogg"; const ASSET_SWITCH: &str = "sounds/typosonic-typing-192811-crop.ogg"; const ASSET_INCOMING_MESSAGE: &str = "sounds/connect.ogg"; const ASSET_PING: &str = "sounds/connect.ogg"; const ASSET_CONNECT: &str = "sounds/connect.ogg"; const ASSET_RADIO: &str = "external/LP - Girls Go Wild (Official Music Video) [M7XRN0oHGIM].mp3"; const ASSET_BGM: &str = "external/Ben Prunty - FTL - 12 Void (Explore).mp3"; const ASSET_THRUSTER: &str = "sounds/thruster.ogg"; const ASSET_ROCKET: &str = "sounds/rocket.ogg"; const ASSET_WAKEUP: &str = "sounds/wakeup.ogg"; const ASSET_BIKESTART: &str = "sounds/bikestart.ogg"; pub struct AudioPlugin; impl Plugin for AudioPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, setup); app.add_systems(Update, toggle_bgm); app.add_systems(PostUpdate, play_sfx); app.add_systems(PostUpdate, update_music); app.add_event::(); app.add_event::(); } } pub enum Sfx { IncomingChatMessage, Click, Switch, Ping, Connect, EnterVehicle, None, } #[derive(Event)] pub struct PlaySfxEvent(pub Sfx); #[derive(Event)] pub struct ToggleMusicEvent(); #[derive(Component)] pub struct ComponentBGM; #[derive(Component)] pub struct ComponentRadio; #[derive(Component)] pub struct ComponentThrusterSound; #[derive(Component)] pub struct ComponentRocketSound; #[derive(Component)] struct SoundBGM(Handle); #[derive(Component)] pub struct SoundRadio(Handle); #[derive(Resource)] pub struct SoundClick(Handle); #[derive(Resource)] pub struct SoundSwitch(Handle); #[derive(Resource)] pub struct SoundIncomingMessage(Handle); #[derive(Resource)] pub struct SoundPing(Handle); #[derive(Resource)] pub struct SoundConnect(Handle); #[derive(Resource)] pub struct SoundBikeStart(Handle); pub fn setup( mut commands: Commands, settings: Res, asset_server: Res, ) { commands.spawn(( ComponentBGM, AudioBundle { source: SoundBGM(asset_server.load(ASSET_BGM)).0.clone(), settings: PlaybackSettings { mode: PlaybackMode::Loop, paused: settings.hud_active || settings.mute_music, ..default() }, }, )); commands.spawn(( ComponentRadio, AudioBundle { source: SoundBGM(asset_server.load(ASSET_RADIO)).0.clone(), settings: PlaybackSettings { mode: PlaybackMode::Loop, paused: !settings.hud_active || settings.mute_music, ..default() }, }, )); if !settings.mute_sfx { commands.spawn(( AudioBundle { source: asset_server.load(ASSET_WAKEUP), settings: PlaybackSettings::DESPAWN, }, )); } commands.spawn(( ComponentThrusterSound, AudioBundle { source: asset_server.load(ASSET_THRUSTER), settings: PlaybackSettings { mode: PlaybackMode::Loop, paused: true, ..default() }, }, )); commands.spawn(( ComponentRocketSound, AudioBundle { source: asset_server.load(ASSET_ROCKET), settings: PlaybackSettings { mode: PlaybackMode::Loop, paused: true, ..default() }, }, )); commands.insert_resource(SoundClick(asset_server.load(ASSET_CLICK))); commands.insert_resource(SoundSwitch(asset_server.load(ASSET_SWITCH))); commands.insert_resource(SoundIncomingMessage(asset_server.load(ASSET_INCOMING_MESSAGE))); commands.insert_resource(SoundPing(asset_server.load(ASSET_PING))); commands.insert_resource(SoundConnect(asset_server.load(ASSET_CONNECT))); commands.insert_resource(SoundBikeStart(asset_server.load(ASSET_BIKESTART))); } pub fn toggle_bgm( keyboard_input: Res>, mut evwriter_toggle: EventWriter, mut evwriter_sfx: EventWriter, mut settings: ResMut, ) { if keyboard_input.just_pressed(KeyCode::KeyT) { settings.mute_music ^= true; evwriter_sfx.send(PlaySfxEvent(Sfx::Click)); evwriter_toggle.send(ToggleMusicEvent()); } if keyboard_input.just_pressed(KeyCode::KeyM) { settings.mute_sfx ^= true; evwriter_sfx.send(PlaySfxEvent(Sfx::Click)); evwriter_toggle.send(ToggleMusicEvent()); } } pub fn play_sfx( mut commands: Commands, settings: Res, mut events_sfx: EventReader, sound_click: Res, sound_switch: Res, sound_incoming_message: Res, sound_ping: Res, sound_connect: Res, sound_bikestart: Res, ) { if settings.mute_sfx && !events_sfx.is_empty() { events_sfx.clear(); } for sfx in events_sfx.read() { match sfx.0 { Sfx::None => { continue; } _ => {} } commands.spawn(AudioBundle { source: match sfx.0 { Sfx::Switch => sound_switch.0.clone(), Sfx::Click => sound_click.0.clone(), Sfx::IncomingChatMessage => sound_incoming_message.0.clone(), Sfx::Ping => sound_ping.0.clone(), Sfx::Connect => sound_connect.0.clone(), Sfx::EnterVehicle => sound_bikestart.0.clone(), Sfx::None => sound_ping.0.clone(), }, settings: PlaybackSettings::DESPAWN, }); } } pub fn str2sfx(sfx_label: &str) -> Sfx { return match sfx_label { "switch" => Sfx::Switch, "click" => Sfx::Click, "chat" => Sfx::IncomingChatMessage, "ping" => Sfx::Ping, "connect" => Sfx::Connect, "entervehicle" => Sfx::EnterVehicle, _ => Sfx::None, }; } pub fn update_music( mut events: EventReader, bgm_controller: Query<&AudioSink, With>, radio_controller: Query<&AudioSink, With>, settings: Res, ) { if !events.is_empty() { events.clear(); if let Ok(bgm_sink) = bgm_controller.get_single() { if let Ok(radio_sink) = radio_controller.get_single() { if settings.mute_music { radio_sink.pause(); bgm_sink.pause(); } else { if settings.hud_active { radio_sink.play(); bgm_sink.pause(); println!("pausing"); } else { radio_sink.pause(); bgm_sink.play(); println!("playing"); } } } } } }