Skip to content

Commit 411f17a

Browse files
IceSentryItsDoot
authored andcommitted
Add simple collision sound to breakout (bevyengine#4331)
# Objective - Add sound effect to the breakout example ## Solution - Add a collision event and a system that listens to the event and plays a sound I only added a single sound for all collisions for the sake of simplicity, but this could easily be extended to play a different sound depending on the type of entity hit. The sound was generated randomly by using https://sfxr.me https://sfxr.me/#11111GA9soYREjtsWhzjPrpMDEYSjX8Fo1E6PnKhxdw6tu869XW4EAc3nzpKVAYLMzToNcHQtQjeBqjZukqPmMDToGdYQQCWBnC3nEYfp53se5ep9btxRdLK Closes bevyengine#4326 https://user-images.githubusercontent.com/8348954/160154727-00e30743-3385-4c2f-97f0-1aaaf9a4dcc5.mp4 For some reason the video has a lot of delay in the sound, but when playing it locally there's no delay --- ## Changelog - Added sound to breakout example - Added bevy_audio and vorbis to the feature list ran for examples in CI ## Migration Guide N/A
1 parent 3cc930a commit 411f17a

File tree

3 files changed

+31
-4
lines changed

3 files changed

+31
-4
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,13 @@ jobs:
274274
toolchain: stable
275275
- name: Build bevy
276276
run: |
277-
cargo build --no-default-features --features "bevy_dynamic_plugin,bevy_gilrs,bevy_gltf,bevy_winit,render,png,hdr,x11,bevy_ci_testing,trace,trace_chrome"
277+
cargo build --no-default-features --features "bevy_dynamic_plugin,bevy_gilrs,bevy_gltf,bevy_winit,render,png,hdr,x11,bevy_ci_testing,trace,trace_chrome,bevy_audio,vorbis"
278278
- name: Run examples
279279
run: |
280280
for example in .github/example-run/*.ron; do
281281
example_name=`basename $example .ron`
282282
echo "running $example_name - "`date`
283-
time CI_TESTING_CONFIG=$example xvfb-run cargo run --example $example_name --no-default-features --features "bevy_dynamic_plugin,bevy_gilrs,bevy_gltf,bevy_winit,render,png,hdr,x11,bevy_ci_testing,trace,trace_chrome"
283+
time CI_TESTING_CONFIG=$example xvfb-run cargo run --example $example_name --no-default-features --features "bevy_dynamic_plugin,bevy_gilrs,bevy_gltf,bevy_winit,render,png,hdr,x11,bevy_ci_testing,trace,trace_chrome,bevy_audio,vorbis"
284284
sleep 10
285285
done
286286
zip traces.zip trace*.json

assets/sounds/breakout_collision.ogg

4.81 KB
Binary file not shown.

examples/games/breakout.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ fn main() {
5858
.insert_resource(Scoreboard { score: 0 })
5959
.insert_resource(ClearColor(BACKGROUND_COLOR))
6060
.add_startup_system(setup)
61+
.add_event::<CollisionEvent>()
6162
.add_system_set(
6263
SystemSet::new()
6364
.with_run_criteria(FixedTimestep::step(TIME_STEP as f64))
6465
.with_system(check_for_collisions)
6566
.with_system(move_paddle.before(check_for_collisions))
66-
.with_system(apply_velocity.before(check_for_collisions)),
67+
.with_system(apply_velocity.before(check_for_collisions))
68+
.with_system(play_collision_sound.after(check_for_collisions)),
6769
)
6870
.add_system(update_scoreboard)
6971
.add_system(bevy::input::system::exit_on_esc_system)
@@ -82,9 +84,14 @@ struct Velocity(Vec2);
8284
#[derive(Component)]
8385
struct Collider;
8486

87+
#[derive(Default)]
88+
struct CollisionEvent;
89+
8590
#[derive(Component)]
8691
struct Brick;
8792

93+
struct CollisionSound(Handle<AudioSource>);
94+
8895
// This bundle is a collection of the components that define a "wall" in our game
8996
#[derive(Bundle)]
9097
struct WallBundle {
@@ -167,6 +174,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
167174
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
168175
commands.spawn_bundle(UiCameraBundle::default());
169176

177+
// Sound
178+
let ball_collision_sound = asset_server.load("sounds/breakout_collision.ogg");
179+
commands.insert_resource(CollisionSound(ball_collision_sound));
180+
170181
// Paddle
171182
let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
172183

@@ -268,7 +279,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
268279
// the space on the top and sides of the bricks only captures a lower bound, not an exact value
269280
let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0;
270281
let left_edge_of_bricks = center_of_bricks
271-
// Space taken up by the bricks
282+
// Space taken up by the bricks
272283
- (n_columns as f32 / 2.0 * BRICK_SIZE.x)
273284
// Space taken up by the gaps
274285
- n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS;
@@ -349,6 +360,7 @@ fn check_for_collisions(
349360
mut scoreboard: ResMut<Scoreboard>,
350361
mut ball_query: Query<(&mut Velocity, &Transform), With<Ball>>,
351362
collider_query: Query<(Entity, &Transform, Option<&Brick>), With<Collider>>,
363+
mut collision_events: EventWriter<CollisionEvent>,
352364
) {
353365
let (mut ball_velocity, ball_transform) = ball_query.single_mut();
354366
let ball_size = ball_transform.scale.truncate();
@@ -362,6 +374,9 @@ fn check_for_collisions(
362374
transform.scale.truncate(),
363375
);
364376
if let Some(collision) = collision {
377+
// Sends a collision event so that other systems can react to the collision
378+
collision_events.send_default();
379+
365380
// Bricks should be despawned and increment the scoreboard on collision
366381
if maybe_brick.is_some() {
367382
scoreboard.score += 1;
@@ -394,3 +409,15 @@ fn check_for_collisions(
394409
}
395410
}
396411
}
412+
413+
fn play_collision_sound(
414+
mut collision_events: EventReader<CollisionEvent>,
415+
audio: Res<Audio>,
416+
sound: Res<CollisionSound>,
417+
) {
418+
// Play a sound once per frame if a collision occurred. `count` consumes the
419+
// events, preventing them from triggering a sound on the next frame.
420+
if collision_events.iter().count() > 0 {
421+
audio.play(sound.0.clone());
422+
}
423+
}

0 commit comments

Comments
 (0)