Jumping
Load an Audio Asset
We'll create a new resource to hold the handles to audio assets, and load it in the load_assets
system.
#![allow(unused)] fn main() { extern crate bevy; use bevy::prelude::*; #[derive(Resource)] struct AudioAssets { jump: Handle<AudioSource>, } fn load_assets( mut commands: Commands, asset_server: Res<AssetServer>, // ... ) { commands.insert_resource(AudioAssets { jump: asset_server.load("jump.wav"), }); // ... } }
The build-in type for audio is AudioSource
.
Trigger an Event to Play Audio
We'll trigger an event when we want to play audio. For now, that is when the player is starting to jump. To avoid triggering to many events, we should make sure that the player was not already jumping.
We'll start by declaring an event type:
#![allow(unused)] fn main() { extern crate bevy; use bevy::prelude::*; #[derive(Event)] enum AudioTrigger { Jump, } }
To send an event, we can use the EventWriter
system parameter:
#![allow(unused)] fn main() { extern crate bevy; use bevy::prelude::*; #[derive(Event)] enum AudioTrigger {Jump} #[derive(Component)] struct Velocity {jumping: f32} #[derive(Component)] struct IsOnGround(f32); #[derive(Component)] struct Player; fn control_player( keyboard_input: Res<ButtonInput<KeyCode>>, mut player: Query<(&mut Velocity, &IsOnGround), With<Player>>, time: Res<Time>, mut audio_triggers: EventWriter<AudioTrigger>, ) { // ... let mut velocity = Velocity { jumping: 0.0 }; let is_on_ground = IsOnGround(0.0); if time.elapsed_secs() - is_on_ground.0 < 0.5 && keyboard_input.pressed(KeyCode::Space) { if velocity.jumping == 0.0 { audio_triggers.send(AudioTrigger::Jump); } velocity.jumping = 15.0; } } }
Play Audio when Receiving the Event
To receive an event, we must use the EventReader
system parameter, and by calling EventReader::read
we can iterate over events.
To play audio, we must spawn an entity with the AudioPlayer
component that will contain an Handle
to the AudioSource
asset.
By default, audio entities remain present once the audio is done playing. You can change this behaviour with the component PlaybackSettings::DESPAWN
.
#![allow(unused)] fn main() { extern crate bevy; use bevy::prelude::*; #[derive(Event)] enum AudioTrigger {Jump} #[derive(Resource)] struct AudioAssets { jump: Handle<AudioSource> } fn play_audio( mut commands: Commands, mut audio_triggers: EventReader<AudioTrigger>, sound_assets: Res<AudioAssets>, ) { for trigger in audio_triggers.read() { match trigger { AudioTrigger::Jump => { commands.spawn(( AudioPlayer::<AudioSource>(sound_assets.jump.clone()), PlaybackSettings::DESPAWN, )); } } } } }
We'll start a new plugin for all the audio related actions. Unlike events used with triggers and observers, events used with EventWriter
and EventReader
must be registered in the application with App::add_event
. The plugin will register the event and add the system.
#![allow(unused)] fn main() { extern crate bevy; use bevy::prelude::*; #[derive(Event)] enum AudioTrigger {Jump} fn play_audio() {} fn audio_plugin(app: &mut App) { app.add_event::<AudioTrigger>() .add_systems(Update, play_audio); } }