use bevy::ecs::system::Resource; use bevy::prelude::*; use bevy_kira_audio::AudioSource; use serde::{Deserialize, Serialize}; use crate::music_box::MusicBox; pub trait SuppliesAudio: Resource { fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>>; } #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub struct AudioSettings { master_volume: f32, music_volume: f32, sfx_volume: f32, ui_volume: f32, } impl Default for AudioSettings { fn default() -> Self { Self { master_volume: 1.0, music_volume: 0.0, sfx_volume: 0.0, ui_volume: 0.0, } } } #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub enum CrossFadeTrack { #[default] A, B, } #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub struct CrossFadeState { pub active: CrossFadeTrack, pub next: CrossFadeTrack, pub progress: f32, } impl Default for CrossFadeState { fn default() -> Self { Self { active: CrossFadeTrack::A, next: CrossFadeTrack::B, progress: 0.0, } } } #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct AudioCrossFade { pub music: CrossFadeState, pub ambiance: CrossFadeState, } pub enum TrackType { Single(Handle<AudioSource>), WithIntro(Handle<AudioSource>, Handle<AudioSource>), Missing, } impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> { pub fn resolve_track_name<Name: ToString>(&'w self, name: Name) -> TrackType { let name = name.to_string(); if let (Some(intro), Some(looped)) = ( self.handles.get_audio_track(format!("{}_intro", &name)), self.handles.get_audio_track(format!("{}_loop", &name)), ) { TrackType::WithIntro(intro, looped) } else if let Some(track) = self.handles.get_audio_track(name.clone()) { TrackType::Single(track) } else if let Some(track) = self.handles.get_audio_track(format!("{}_looped", name)) { TrackType::Single(track) } else { TrackType::Missing } } } impl SuppliesAudio for AssetServer { fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>> { Some(self.load(&name.to_string())) } }