Physics & Audio
Integrate physics simulation and audio in Bevy - colliders, rigid bodies, and sound triggers.
Recipe
// Physics (conceptual Avian/Rapier-style):
// commands.spawn((
// RigidBody::Dynamic,
// Collider::sphere(0.5),
// Transform::default(),
// ));
// Audio:
fn play_jump(asset_server: Res<AssetServer>, mut commands: Commands) {
commands.spawn((
AudioPlayer::new(asset_server.load("audio/jump.ogg")),
PlaybackSettings::DESPAWN,
));
}When to reach for this:
- Platformers and 3D games needing collision
- Puzzles with realistic stacking or triggers
- Action games with responsive SFX and music layers
- VR/desktop titles with spatial audio cues
Working Example
Event-driven audio on jump:
use bevy::prelude::*;
#[derive(Event)]
struct JumpEvent;
fn play_jump_sfx(
mut events: EventReader<JumpEvent>,
asset_server: Res<AssetServer>,
mut commands: Commands,
) {
for _ in events.read() {
commands.spawn((
AudioPlayer::new(asset_server.load("audio/jump.ogg")),
PlaybackSettings::DESPAWN,
));
}
}What this demonstrates:
- One-shot audio entity despawns after playback
- Decoupled jump logic fires event; audio system listens
- Asset path consistent with
assets/audio/folder
Deep Dive
How It Works
- Physics plugin steps simulation in
FixedUpdateschedule. - Colliders generate contact events for gameplay (damage, footstep).
- Audio mixes streams;
AudioPlayerstarts playback on spawn. - Listener component on camera affects 3D pan/volume.
Integration Points
| System | Schedule |
|---|---|
| Physics step | FixedUpdate |
| SFX spawn | Update on events |
| Music loop | Persistent entity with PlaybackSettings::LOOP |
Gotchas
- Physics in variable
Update- tunneling at high speed. Fix: only integrate inFixedUpdate. - Collider mesh mismatch with sprite - unfair hits. Fix: debug draw colliders in dev builds.
- Too many simultaneous voices - mixer clipping. Fix: pool SFX channels; priority system.
- Large uncompressed WAV - load stutter. Fix: OGG/Vorbis compressed assets.
- Forgetting listener entity - 3D audio flat. Fix: attach
AudioListenerto active camera.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Custom AABB collision | Simple tile game | Many dynamic bodies |
| FMOD/Wwise via FFI | AAA audio tooling | Small indie scope |
| 2D grid collision manual | Retro grid movement | Physics realism needed |
| No audio | Silent prototype | Ship to players |
FAQs
Which physics crate?
avian (Bevy 0.14+ ecosystem) or bevy_rapier3d/2d - pick one per project and pin version to Bevy release.
Kinematic vs dynamic?
Kinematic for player-controlled that pushes physics; dynamic for crates and ragdolls.
Collision layers?
Collision groups/masks filter what interacts - define in plugin config to reduce work.
Music crossfade?
Two AudioPlayer entities; tween volumes over 1-2 seconds on state change.
Pause audio?
Global volume resource or pause all players when GameState::Paused.
Physics events?
CollisionStarted/Ended events from plugin map to damage or footstep sounds.
Determinism?
Fixed timestep helps; full network determinism needs fixed-point and controlled ordering.
Performance?
Sleeping bodies, simplified colliders, broadphase tuning - see performance page.
Timing?
Game Loops & Timing for FixedUpdate wiring.
Assets?
Assets & Scenes for audio file organization.
Related
- Game Loops & Timing - fixed step
- Input & Events - trigger events
- Bevy Engine - schedules
- Assets & Scenes - load audio
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.