Add ship thruster sound

The player's Ship now has an AudioPlayer component constantly looping a
thruster sound effect. It starts paused and is only resumed when the
player fires the thruster.

As noted in the TODO comment at the top of the input_ship_thruster(...)
system, I need to figure out if I want to start using the `Single<>`
query parameter instead of a `Query<>` and then doing my own
null-ability checks (like what it does now).
This commit is contained in:
2025-12-17 17:18:18 -06:00
parent d7802bdbed
commit de75e25ca6
3 changed files with 34 additions and 3 deletions

View File

@@ -111,14 +111,28 @@ fn spawn_camera(mut commands: Commands) {
/// Checks if "W" is pressed and increases velocity accordingly.
fn input_ship_thruster(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<(&mut physics::Velocity, &Transform, &mut Children), With<Ship>>,
mut query: Query<
(
&mut physics::Velocity,
&Transform,
Option<&mut AudioSink>,
&mut Children,
),
With<Ship>,
>,
mut commands: Commands,
game_assets: Res<GameAssets>,
) {
// TODO: Maybe change for a Single<Ship>> so this only runs for the one ship
// buuut... that would silently do nothing if there are 0 or >1 ships, and
// I might want to crash on purpose in that case.
let Ok((mut velocity, transform, children)) = query.single_mut() else {
//
// The AudioSink component doesn't exist for just one frame, forcing it to
// be an optional system parameter. I'm not sure if I want to guard it with
// a check like it does now, or finally switch to using a Single<...> query
// parameter. I would lose ship control if the sound sink didn't spawn, but
// that should be fine -- any time that fails, more has likely also failed.
let Ok((mut velocity, transform, audio, children)) = query.single_mut() else {
let count = query.iter().count();
panic!("There should be exactly one player ship! Instead, there seems to be {count}.");
};
@@ -132,10 +146,16 @@ fn input_ship_thruster(
commands
.entity(*thrusters)
.insert(MeshMaterial2d(game_assets.thruster_mat_active()));
if let Some(audio) = audio {
audio.play();
}
} else {
commands
.entity(*thrusters)
.insert(MeshMaterial2d(game_assets.thruster_mat_inactive()));
if let Some(audio) = audio {
audio.pause();
}
}
}

View File

@@ -168,6 +168,12 @@ pub fn spawn_player(mut commands: Commands, game_assets: Res<GameAssets>) {
Mesh2d(game_assets.ship().0),
MeshMaterial2d(game_assets.ship().1),
Transform::default().with_scale(Vec3::new(20.0, 20.0, 20.0)),
AudioPlayer::new(game_assets.ship_thruster_sound()),
PlaybackSettings {
mode: bevy::audio::PlaybackMode::Loop,
paused: true,
..Default::default()
},
))
.with_child((
Mesh2d(game_assets.thruster_mesh()),

View File

@@ -58,7 +58,7 @@ impl Default for WorldSize {
pub struct GameAssets {
meshes: [Handle<Mesh>; 5],
materials: [Handle<ColorMaterial>; 7],
sounds: [Handle<AudioSource>; 3],
sounds: [Handle<AudioSource>; 4],
}
impl GameAssets {
@@ -109,6 +109,10 @@ impl GameAssets {
pub fn asteroid_crack_sound(&self) -> Handle<AudioSource> {
self.sounds[2].clone()
}
pub fn ship_thruster_sound(&self) -> Handle<AudioSource> {
self.sounds[3].clone()
}
}
impl FromWorld for GameAssets {
@@ -141,6 +145,7 @@ impl FromWorld for GameAssets {
loader.load("explosionCrunch_004.ogg"),
loader.load("laserSmall_001.ogg"),
loader.load("explosionCrunch_000.ogg"),
loader.load("thrusterFire_004.ogg"),
];
GameAssets {
meshes,