Skip to content

Commit

Permalink
✨ audio
Browse files Browse the repository at this point in the history
  • Loading branch information
fabienjuif authored Dec 9, 2023
1 parent 9260e93 commit 73ff91b
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 34 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ I aim to explore every aspect of building a game with Bevy without having a spec

- [x] Implement a satisfactory camera (refer to [bevy-cameraman](https://github.com/fabienjuif/bevy_cameraman))
- [x] Integrate physics/collision mechanics
- [x] Audio
- [ ] Develop responsive player control/kinematics
- [ ] Incorporate particle systems
- [ ] Explore networking capabilities
Expand Down
5 changes: 5 additions & 0 deletions assets/credits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Credits

## Audio

- [explosion.ogg](https://freesound.org/people/Werra/sounds/244394/) - edited
Binary file added assets/sounds/explosion.ogg
Binary file not shown.
48 changes: 48 additions & 0 deletions src/audio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use bevy::prelude::*;
use bevy_cameraman::Cameraman;

const DEBUG: bool = false;

pub struct AudioPlugin;

impl Plugin for AudioPlugin {
fn build(&self, app: &mut App) {
app.add_systems(PostStartup, setup);
}
}

fn setup(mut commands: Commands, query_camera: Query<Entity, With<Cameraman>>) {
let gap = 200.;
let listener = SpatialListener::new(gap);

for entity in &query_camera {
let mut cmd = commands.entity(entity);
let cmd = cmd.insert((SpatialBundle::default(), listener.clone()));

if DEBUG {
cmd.with_children(|parent| {
// left ear
parent.spawn(SpriteBundle {
sprite: Sprite {
color: Color::RED,
custom_size: Some(Vec2::splat(20.0)),
..default()
},
transform: Transform::from_xyz(-gap / 2.0, 0.0, 0.0),
..default()
});

// right ear
parent.spawn(SpriteBundle {
sprite: Sprite {
color: Color::GREEN,
custom_size: Some(Vec2::splat(20.0)),
..default()
},
transform: Transform::from_xyz(gap / 2.0, 0.0, 0.0),
..default()
});
});
}
}
}
26 changes: 21 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod audio;
mod castles;
mod common;
mod health;
Expand All @@ -7,6 +8,7 @@ mod player;
mod racks;
mod teams;

use audio::AudioPlugin;
use bevy::{
log::{Level, LogPlugin},
prelude::*,
Expand All @@ -24,16 +26,29 @@ use racks::RacksPlugin;
use teams::TeamsPlugin;
use xxhash_rust::xxh3::xxh3_64;

const AUDIO_SCALE: f32 = 1. / 100.0;

fn main() {
let mut app = App::new();
let seed = b"13U2x";

app.add_plugins((
DefaultPlugins.set(LogPlugin {
level: Level::TRACE,
filter: "wgpu=error,bevy_render=warn,bevy_app=warn,bevy_ecs=warn,naga=warn,gilrs=warn,game::health=info,game::racks=info"
.to_string(),
}),
DefaultPlugins
.set(LogPlugin {
level: Level::TRACE,
filter: [
"wgpu=error",
"bevy_render=warn,bevy_app=warn,bevy_ecs=warn",
"naga=warn",
"gilrs=warn",
"game::health=info,game::racks=info",
]
.join(","),
})
.set(bevy::audio::AudioPlugin {
spatial_scale: bevy::audio::SpatialScale::new_2d(AUDIO_SCALE),
..default()
}),
RngPlugin::new().with_rng_seed(xxh3_64(seed)),
PhysicsPlugin,
TeamsPlugin,
Expand All @@ -42,6 +57,7 @@ fn main() {
CastlesPlugin,
HealthPlugin,
LocalPlayerPlugin,
AudioPlugin,
))
// --- camera ---
.add_plugins((
Expand Down
40 changes: 30 additions & 10 deletions src/minions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const DESTROY_MINIONS_AFTER_SECS: f32 = 120.;
const DECAY_VALUE_PER_SEC: f32 = 10.;
const REWARDS_GOLD: f32 = 1.;

const EXPLOSION_AUDIO_ID: &str = "sounds/explosion.ogg";

pub struct MinionsPlugin;

// TODO: move this into common
Expand All @@ -25,21 +27,30 @@ struct Minion {
had_exploded: bool,
}

#[derive(Resource)]
struct AudioExplosion(Handle<AudioSource>);

impl Plugin for MinionsPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
Update,
(
update_move_minions,
check_collisions_minions,
decay_life,
explosion_damage,
),
)
.add_systems(PostUpdate, (destroy_minions, destroy_after_timer));
app.add_systems(Startup, setup_audio)
.add_systems(
Update,
(
update_move_minions,
check_collisions_minions,
decay_life,
explosion_damage,
),
)
.add_systems(PostUpdate, (destroy_minions, destroy_after_timer));
}
}

fn setup_audio(mut commands: Commands, server: Res<AssetServer>) {
let handle = server.load(EXPLOSION_AUDIO_ID);
commands.insert_resource(AudioExplosion(handle));
}

#[derive(Bundle)]
pub struct MinionBundle {
minion: Minion,
Expand Down Expand Up @@ -111,12 +122,14 @@ struct ExplosionBundle {
sensor: Sensor,
collider: Collider,
timer_destroyable: TimeDestroyable,
audio: AudioBundle,
}

impl ExplosionBundle {
pub fn new(
meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<ColorMaterial>>,
audio_asset: &Handle<AudioSource>,
mut translation: Vec3,
team: Team,
) -> Self {
Expand All @@ -138,6 +151,10 @@ impl ExplosionBundle {
timer_destroyable: TimeDestroyable {
timer: Timer::from_seconds(0.2, bevy::time::TimerMode::Once),
},
audio: AudioBundle {
source: audio_asset.clone(),
settings: PlaybackSettings::ONCE.with_spatial(true),
},
}
}
}
Expand Down Expand Up @@ -239,6 +256,7 @@ fn check_collisions_minions(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
audio_explosion: Res<AudioExplosion>,
mut collision_events: EventReader<CollisionEvent>,
// queries
mut query_minions: Query<(&Transform, &Team, &mut Minion), With<Minion>>,
Expand Down Expand Up @@ -268,6 +286,7 @@ fn check_collisions_minions(
commands.spawn(ExplosionBundle::new(
&mut meshes,
&mut materials,
&audio_explosion.0,
transform_a.translation,
team_a.clone(),
));
Expand Down Expand Up @@ -305,6 +324,7 @@ fn check_collisions_minions(
commands.spawn(ExplosionBundle::new(
&mut meshes,
&mut materials,
&audio_explosion.0,
minion_transform.translation,
minion_team.clone(),
));
Expand Down
58 changes: 39 additions & 19 deletions web/index.html
Original file line number Diff line number Diff line change
@@ -1,50 +1,70 @@
<html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>An other bevy 2D game</title>
<style>
body {
background: linear-gradient(
45deg,
#4b0082 0%,
#8a2be2 100%
);
background: linear-gradient(45deg, #4b0082 0%, #8a2be2 100%);
background-repeat: no-repeat;
background-size: cover;
height: 100vh;
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
color: #ffffff;
}

h1 {
font-size: 2.5em;
text-align: center;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
padding: 2em;
margin: 0; /* Remove default margin for better alignment */
}
canvas {
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
outline: none;

button {
background-color: #ff8c00;
color: #ffffff;
font-size: 1.5em;
padding: 0.5em 1em;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}

button:hover {
background-color: #ffa500;
}
</style>
</head>
<body>
<h1>An other bevy 2D game</h1>
<button onclick="play()">Play</button>
<script type="module">
import init from './wasm_game.js'
init()
</script>
<script>
interval = setInterval(function () {
let canvas = document.getElementsByTagName("canvas")[0]
import init from "./wasm_game.js";

window.play = function () {
// Hide header and button
document.querySelector("h1").style.display = "none";
document.querySelector("button").style.display = "none";

// Call your initialization function
init();

// Focus on the canvas
let interval = setInterval(function () {
let canvas = document.getElementsByTagName("canvas")[0];
if (canvas) {
canvas.focus()
clearInterval(interval)
canvas.focus();
clearInterval(interval);
}
}, 100)
}, 100);
};
</script>
</body>
</html>

0 comments on commit 73ff91b

Please sign in to comment.