use {
bevy::{
prelude::{
default, shape, App, Assets, Camera3dBundle, Color, Commands, Component, Deref, Handle,
Mesh, PbrBundle, PointLight, PointLightBundle, PostStartup, Query, Res, ResMut,
Resource, StandardMaterial, Startup, Transform, Update, Vec3, With,
},
time::Time,
DefaultPlugins,
},
bevy_oddio::{
builtins::sine::{self, Sine},
output::spatial::SpatialAudioSink,
Audio, AudioPlugin,
},
oddio::{Sample, Spatial, SpatialOptions},
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(AudioPlugin::new())
.add_systems(Startup, init_assets)
.add_systems(PostStartup, setup)
.add_systems(Update, change_velocity)
.run();
}
#[derive(Component)]
struct Emitter;
#[derive(Resource, Deref)]
struct SineHandle(Handle<Sine>);
#[derive(Resource)]
struct SineSink(Handle<SpatialAudioSink<Sine>>);
fn init_assets(mut commands: Commands, mut assets: ResMut<Assets<Sine>>) {
let handle = assets.add(Sine);
commands.insert_resource(SineHandle(handle));
}
fn setup(
mut commands: Commands,
mut audio: ResMut<Audio<Sample, Sine>>,
noise: Res<SineHandle>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let handle = audio.play_spatial(
noise.clone(),
sine::Settings::new(0.0, 440.0),
SpatialOptions {
position: (Vec3::Y * 0.4).into(),
velocity: Vec3::ZERO.into(),
radius: 0.5,
},
);
commands.insert_resource(SineSink(handle));
commands.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::UVSphere {
radius: 0.2,
..default()
})),
material: materials.add(Color::GREEN.into()),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
});
commands
.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::UVSphere {
radius: 0.2,
..default()
})),
material: materials.add(Color::BLUE.into()),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
})
.insert(Emitter);
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(0.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}
fn change_velocity(
sink: Res<SineSink>,
mut sinks: ResMut<Assets<SpatialAudioSink<Sine>>>,
time: Res<Time>,
mut query: Query<&mut Transform, With<Emitter>>,
) {
let mut emitter = query.single_mut();
let x = time.elapsed_seconds_wrapped().sin() * 3.0;
let z = time.elapsed_seconds_wrapped().cos() * 3.0;
let delta = time.delta_seconds();
let Some(sink) = sinks.get_mut(&sink.0) else {
return;
};
let prev_pos = emitter.translation;
let position = Vec3::new(x, prev_pos.y, z);
let velocity = Vec3::new(
(prev_pos.x - position.x) / delta,
0.0,
(prev_pos.z - position.z) / delta,
);
emitter.translation = Vec3::new(position.x, position.y, position.z);
sink.control::<Spatial<_>, _>()
.set_motion(position.into(), velocity.into(), false);
}