diff --git a/crates/bevy_audio/src/audio.rs b/crates/bevy_audio/src/audio.rs index 7c020a0333fa2..6ff95ec5711e9 100644 --- a/crates/bevy_audio/src/audio.rs +++ b/crates/bevy_audio/src/audio.rs @@ -33,7 +33,7 @@ impl Volume { } /// The way Bevy manages the sound playback. -#[derive(Debug, Clone, Copy, Reflect)] +#[derive(Debug, Clone, Copy, Reflect, Default)] pub enum PlaybackMode { /// Play the sound once. Do nothing when it ends. Once, @@ -42,6 +42,7 @@ pub enum PlaybackMode { /// Despawn the entity and its children when the sound finishes playing. Despawn, /// Remove the audio components from the entity, when the sound finishes playing. + #[default] Remove, } @@ -53,8 +54,6 @@ pub enum PlaybackMode { #[derive(Component, Clone, Copy, Debug, Reflect)] #[reflect(Default, Component, Debug)] pub struct PlaybackSettings { - /// The desired playback behavior. - pub mode: PlaybackMode, /// Volume to play at. pub volume: Volume, /// Speed to play at. @@ -77,40 +76,17 @@ pub struct PlaybackSettings { impl Default for PlaybackSettings { fn default() -> Self { - // TODO: what should the default be: ONCE/DESPAWN/REMOVE? - Self::ONCE + Self { + volume: Volume(1.0), + speed: 1.0, + paused: false, + spatial: false, + spatial_scale: None, + } } } impl PlaybackSettings { - /// Will play the associated audio source once. - pub const ONCE: PlaybackSettings = PlaybackSettings { - mode: PlaybackMode::Once, - volume: Volume(1.0), - speed: 1.0, - paused: false, - spatial: false, - spatial_scale: None, - }; - - /// Will play the associated audio source in a loop. - pub const LOOP: PlaybackSettings = PlaybackSettings { - mode: PlaybackMode::Loop, - ..PlaybackSettings::ONCE - }; - - /// Will play the associated audio source once and despawn the entity afterwards. - pub const DESPAWN: PlaybackSettings = PlaybackSettings { - mode: PlaybackMode::Despawn, - ..PlaybackSettings::ONCE - }; - - /// Will play the associated audio source once and remove the audio components afterwards. - pub const REMOVE: PlaybackSettings = PlaybackSettings { - mode: PlaybackMode::Remove, - ..PlaybackSettings::ONCE - }; - /// Helper to start in a paused state. pub const fn paused(mut self) -> Self { self.paused = true; @@ -251,7 +227,7 @@ pub type AudioBundle = AudioSourceBundle; #[derive(Component, Reflect)] #[reflect(Component)] #[require(PlaybackSettings)] -pub struct AudioPlayer(pub Handle) +pub struct AudioPlayer(pub Handle, pub PlaybackMode) where Source: Asset + Decodable; @@ -260,7 +236,7 @@ where Source: Asset + Decodable, { fn clone(&self) -> Self { - Self(self.0.clone()) + Self(self.0.clone(), self.1) } } @@ -271,7 +247,27 @@ impl AudioPlayer { /// initialize an [`AudioPlayer`] with a different type, just initialize it directly using normal /// tuple struct syntax. pub fn new(source: Handle) -> Self { - Self(source) + Self(source, PlaybackMode::default()) + } + + /// Creates a new [`AudioPlayer`] that plays the sound once. + pub fn with_once(source: Handle) -> Self { + Self(source, PlaybackMode::Once) + } + + /// Creates a new [`AudioPlayer`] that loops the sound forever. + pub fn with_loop(source: Handle) -> Self { + Self(source, PlaybackMode::Loop) + } + + /// Creates a new [`AudioPlayer`] that despawns the entity when the sound finishes playing. + pub fn with_despawn(source: Handle) -> Self { + Self(source, PlaybackMode::Despawn) + } + + /// Creates a new [`AudioPlayer`] that removes the audio component from the entity when the sound finishes playing. + pub fn with_remove(source: Handle) -> Self { + Self(source, PlaybackMode::Remove) } } @@ -314,7 +310,7 @@ impl Clone for AudioSourceBundle { impl Default for AudioSourceBundle { fn default() -> Self { Self { - source: AudioPlayer(Handle::default()), + source: AudioPlayer(Handle::default(), PlaybackMode::Once), settings: Default::default(), } } diff --git a/crates/bevy_audio/src/audio_output.rs b/crates/bevy_audio/src/audio_output.rs index bbb9c5b682133..4861447be1e13 100644 --- a/crates/bevy_audio/src/audio_output.rs +++ b/crates/bevy_audio/src/audio_output.rs @@ -164,7 +164,7 @@ pub(crate) fn play_queued_audio_system( sink.pause(); } - match settings.mode { + match source_handle.1 { PlaybackMode::Loop => { sink.append(audio_source.decoder().repeat_infinite()); commands.entity(entity).insert(SpatialAudioSink { sink }); @@ -204,7 +204,7 @@ pub(crate) fn play_queued_audio_system( sink.pause(); } - match settings.mode { + match source_handle.1 { PlaybackMode::Loop => { sink.append(audio_source.decoder().repeat_infinite()); commands.entity(entity).insert(AudioSink { sink }); diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index 1519987a4b155..cb31d008feda1 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -9,7 +9,7 @@ //! //! ```no_run //! # use bevy_ecs::prelude::*; -//! # use bevy_audio::{AudioPlayer, AudioPlugin, AudioSource, PlaybackSettings}; +//! # use bevy_audio::{AudioPlayer, AudioPlugin, AudioSource}; //! # use bevy_asset::{AssetPlugin, AssetServer}; //! # use bevy_app::{App, AppExit, NoopPluginGroup as MinimalPlugins, Startup}; //! fn main() { @@ -20,10 +20,9 @@ //! } //! //! fn play_background_audio(asset_server: Res, mut commands: Commands) { -//! commands.spawn(( -//! AudioPlayer::new(asset_server.load("background_audio.ogg")), -//! PlaybackSettings::LOOP, -//! )); +//! commands.spawn( +//! AudioPlayer::with_loop(asset_server.load("background_audio.ogg")) +//! ); //! } //! ``` diff --git a/examples/audio/audio.rs b/examples/audio/audio.rs index 7ca6abcdec93c..ff09ce5576c97 100644 --- a/examples/audio/audio.rs +++ b/examples/audio/audio.rs @@ -11,7 +11,7 @@ fn main() { } fn setup(asset_server: Res, mut commands: Commands) { - commands.spawn(AudioPlayer::new( + commands.spawn(AudioPlayer::with_once( asset_server.load("sounds/Windless Slopes.ogg"), )); } diff --git a/examples/audio/decodable.rs b/examples/audio/decodable.rs index b26952ad06b32..f262070c97c95 100644 --- a/examples/audio/decodable.rs +++ b/examples/audio/decodable.rs @@ -1,7 +1,7 @@ //! Shows how to create a custom [`Decodable`] type by implementing a Sine wave. use bevy::{ - audio::{AddAudioSource, AudioPlugin, Source}, + audio::{AddAudioSource, AudioPlugin, PlaybackMode, Source}, math::ops, prelude::*, reflect::TypePath, @@ -99,5 +99,5 @@ fn setup(mut assets: ResMut>, mut commands: Commands) { let audio_handle = assets.add(SineAudio { frequency: 440., // this is the frequency of A4 }); - commands.spawn(AudioPlayer(audio_handle)); + commands.spawn(AudioPlayer(audio_handle, PlaybackMode::Once)); } diff --git a/examples/audio/pitch.rs b/examples/audio/pitch.rs index 06aeccc3f4ea2..00818f4d82b03 100644 --- a/examples/audio/pitch.rs +++ b/examples/audio/pitch.rs @@ -1,6 +1,6 @@ //! This example illustrates how to play a single-frequency sound (aka a pitch) -use bevy::prelude::*; +use bevy::{audio::PlaybackMode, prelude::*}; use std::time::Duration; fn main() { @@ -30,9 +30,9 @@ fn play_pitch( ) { for _ in events.read() { info!("playing pitch with frequency: {}", frequency.0); - commands.spawn(( - AudioPlayer(pitch_assets.add(Pitch::new(frequency.0, Duration::new(1, 0)))), - PlaybackSettings::DESPAWN, + commands.spawn(AudioPlayer( + pitch_assets.add(Pitch::new(frequency.0, Duration::new(1, 0))), + PlaybackMode::Despawn, )); info!("number of pitch assets: {}", pitch_assets.len()); } diff --git a/examples/audio/soundtrack.rs b/examples/audio/soundtrack.rs index 0108594d94588..2aa1546eb9267 100644 --- a/examples/audio/soundtrack.rs +++ b/examples/audio/soundtrack.rs @@ -79,9 +79,8 @@ fn change_track( match game_state.as_ref() { GameState::Peaceful => { commands.spawn(( - AudioPlayer(soundtrack_player.track_list.first().unwrap().clone()), + AudioPlayer::with_loop(soundtrack_player.track_list.first().unwrap().clone()), PlaybackSettings { - mode: bevy::audio::PlaybackMode::Loop, volume: bevy::audio::Volume::ZERO, ..default() }, @@ -90,9 +89,8 @@ fn change_track( } GameState::Battle => { commands.spawn(( - AudioPlayer(soundtrack_player.track_list.get(1).unwrap().clone()), + AudioPlayer::with_loop(soundtrack_player.track_list.get(1).unwrap().clone()), PlaybackSettings { - mode: bevy::audio::PlaybackMode::Loop, volume: bevy::audio::Volume::ZERO, ..default() }, diff --git a/examples/audio/spatial_audio_2d.rs b/examples/audio/spatial_audio_2d.rs index f0cedc9b9bee3..18ec4902c9fb9 100644 --- a/examples/audio/spatial_audio_2d.rs +++ b/examples/audio/spatial_audio_2d.rs @@ -38,8 +38,8 @@ fn setup( MeshMaterial2d(materials.add(Color::from(BLUE))), Transform::from_translation(Vec3::new(0.0, 50.0, 0.0)), Emitter::default(), - AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")), - PlaybackSettings::LOOP.with_spatial(true), + AudioPlayer::with_loop(asset_server.load("sounds/Windless Slopes.ogg")), + PlaybackSettings::default().with_spatial(true), )); let listener = SpatialListener::new(gap); diff --git a/examples/audio/spatial_audio_3d.rs b/examples/audio/spatial_audio_3d.rs index 5ea1b6035c541..f8a175b0f6dd7 100644 --- a/examples/audio/spatial_audio_3d.rs +++ b/examples/audio/spatial_audio_3d.rs @@ -29,8 +29,8 @@ fn setup( MeshMaterial3d(materials.add(Color::from(BLUE))), Transform::from_xyz(0.0, 0.0, 0.0), Emitter::default(), - AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")), - PlaybackSettings::LOOP.with_spatial(true), + AudioPlayer::with_loop(asset_server.load("sounds/Windless Slopes.ogg")), + PlaybackSettings::default().with_spatial(true), )); let listener = SpatialListener::new(gap); diff --git a/examples/games/breakout.rs b/examples/games/breakout.rs index dc1fd1a9281d0..b62550429046f 100644 --- a/examples/games/breakout.rs +++ b/examples/games/breakout.rs @@ -404,7 +404,7 @@ fn play_collision_sound( if !collision_events.is_empty() { // This prevents events staying active on the next frame. collision_events.clear(); - commands.spawn((AudioPlayer(sound.clone()), PlaybackSettings::DESPAWN)); + commands.spawn(AudioPlayer::with_despawn(sound.clone())); } } diff --git a/examples/mobile/src/lib.rs b/examples/mobile/src/lib.rs index ee49c01c58a25..63c3940be9958 100644 --- a/examples/mobile/src/lib.rs +++ b/examples/mobile/src/lib.rs @@ -165,9 +165,8 @@ fn button_handler( } fn setup_music(asset_server: Res, mut commands: Commands) { - commands.spawn(( - AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")), - PlaybackSettings::LOOP, + commands.spawn(AudioPlayer::with_loop( + asset_server.load("sounds/Windless Slopes.ogg"), )); }