Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/audio/spatial_audio_2d.rs
6592 views
1
//! This example illustrates how to load and play an audio file, and control where the sounds seems to come from.
2
use bevy::{
3
audio::{AudioPlugin, SpatialScale},
4
color::palettes::css::*,
5
prelude::*,
6
time::Stopwatch,
7
};
8
9
/// Spatial audio uses the distance to attenuate the sound volume. In 2D with the default camera,
10
/// 1 pixel is 1 unit of distance, so we use a scale so that 100 pixels is 1 unit of distance for
11
/// audio.
12
const AUDIO_SCALE: f32 = 1. / 100.0;
13
14
fn main() {
15
App::new()
16
.add_plugins(DefaultPlugins.set(AudioPlugin {
17
default_spatial_scale: SpatialScale::new_2d(AUDIO_SCALE),
18
..default()
19
}))
20
.add_systems(Startup, setup)
21
.add_systems(Update, update_emitters)
22
.add_systems(Update, update_listener)
23
.run();
24
}
25
26
fn setup(
27
mut commands: Commands,
28
mut meshes: ResMut<Assets<Mesh>>,
29
mut materials: ResMut<Assets<ColorMaterial>>,
30
asset_server: Res<AssetServer>,
31
) {
32
// Space between the two ears
33
let gap = 400.0;
34
35
// sound emitter
36
commands.spawn((
37
Mesh2d(meshes.add(Circle::new(15.0))),
38
MeshMaterial2d(materials.add(Color::from(BLUE))),
39
Transform::from_translation(Vec3::new(0.0, 50.0, 0.0)),
40
Emitter::default(),
41
AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")),
42
PlaybackSettings::LOOP.with_spatial(true),
43
));
44
45
let listener = SpatialListener::new(gap);
46
commands.spawn((
47
Transform::default(),
48
Visibility::default(),
49
listener.clone(),
50
children![
51
// left ear
52
(
53
Sprite::from_color(RED, Vec2::splat(20.0)),
54
Transform::from_xyz(-gap / 2.0, 0.0, 0.0),
55
),
56
// right ear
57
(
58
Sprite::from_color(LIME, Vec2::splat(20.0)),
59
Transform::from_xyz(gap / 2.0, 0.0, 0.0),
60
)
61
],
62
));
63
64
// example instructions
65
commands.spawn((
66
Text::new("Up/Down/Left/Right: Move Listener\nSpace: Toggle Emitter Movement"),
67
Node {
68
position_type: PositionType::Absolute,
69
bottom: px(12),
70
left: px(12),
71
..default()
72
},
73
));
74
75
// camera
76
commands.spawn(Camera2d);
77
}
78
79
#[derive(Component, Default)]
80
struct Emitter {
81
stopwatch: Stopwatch,
82
}
83
84
fn update_emitters(
85
time: Res<Time>,
86
mut emitters: Query<(&mut Transform, &mut Emitter), With<Emitter>>,
87
keyboard: Res<ButtonInput<KeyCode>>,
88
) {
89
for (mut emitter_transform, mut emitter) in emitters.iter_mut() {
90
if keyboard.just_pressed(KeyCode::Space) {
91
if emitter.stopwatch.is_paused() {
92
emitter.stopwatch.unpause();
93
} else {
94
emitter.stopwatch.pause();
95
}
96
}
97
98
emitter.stopwatch.tick(time.delta());
99
100
if !emitter.stopwatch.is_paused() {
101
emitter_transform.translation.x = ops::sin(emitter.stopwatch.elapsed_secs()) * 500.0;
102
}
103
}
104
}
105
106
fn update_listener(
107
keyboard: Res<ButtonInput<KeyCode>>,
108
time: Res<Time>,
109
mut listener: Single<&mut Transform, With<SpatialListener>>,
110
) {
111
let speed = 200.;
112
113
if keyboard.pressed(KeyCode::ArrowRight) {
114
listener.translation.x += speed * time.delta_secs();
115
}
116
if keyboard.pressed(KeyCode::ArrowLeft) {
117
listener.translation.x -= speed * time.delta_secs();
118
}
119
if keyboard.pressed(KeyCode::ArrowUp) {
120
listener.translation.y += speed * time.delta_secs();
121
}
122
if keyboard.pressed(KeyCode::ArrowDown) {
123
listener.translation.y -= speed * time.delta_secs();
124
}
125
}
126
127