Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<!-- next-header -->
## [Unreleased] - ReleaseDate

## BREAKING CHANGES

- `.play_sfx()` now takes a volume level from `0.0` to `1.0` as a second argument, e.g. `.play_sfx(SfxPreset::Congratulations, 1.0)`

## Other Changes

- (meta) Improved CI times by using sccache together with GitHub Actions caching

## [2.0.1] - 2021-11-15
Expand Down
4 changes: 2 additions & 2 deletions examples/collision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ fn logic(game_state: &mut GameState) {
match event.state {
CollisionState::Begin => {
text_actor.text = format!("{:?}", event.pair);
game_state.audio_manager.play_sfx(SfxPreset::Switch1)
game_state.audio_manager.play_sfx(SfxPreset::Switch1, 1.0)
}
CollisionState::End => {
text_actor.text = "".into();
game_state.audio_manager.play_sfx(SfxPreset::Switch2)
game_state.audio_manager.play_sfx(SfxPreset::Switch2, 1.0)
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions examples/scenarios/car_shoot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fn game_logic(game_state: &mut GameState) {
marble.translation.x = player_x;
marble.layer = 5.0;
marble.collision = true;
game_state.audio_manager.play_sfx(SfxPreset::Impact2);
game_state.audio_manager.play_sfx(SfxPreset::Impact2, 0.7);
}
}

Expand Down Expand Up @@ -151,6 +151,8 @@ fn game_logic(game_state: &mut GameState) {
if event.pair.1.starts_with("marble") {
game_state.string_vec.push(event.pair.1);
}
game_state.audio_manager.play_sfx(SfxPreset::Confirmation1);
game_state
.audio_manager
.play_sfx(SfxPreset::Confirmation1, 0.5);
}
}
8 changes: 5 additions & 3 deletions examples/scenarios/extreme_drivers_ed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,9 @@ fn logic(game_state: &mut GameState) {
event.pair.1.clone()
};
game_state.actors.remove(&shiny_label);
game_state.audio_manager.play_sfx(SfxPreset::Confirmation1);
game_state
.audio_manager
.play_sfx(SfxPreset::Confirmation1, 1.0);
*score += 1;
score_text.text = format!("Score: {}", score);
if *score >= win_amount {
Expand All @@ -1193,14 +1195,14 @@ fn logic(game_state: &mut GameState) {
// Crash!
*game_state.bool_map.get_mut("crashed").unwrap() = true;
//game_state.add_text_actor("crashed", "You crashed. You fail. :-(");
game_state.audio_manager.play_sfx(SfxPreset::Jingle3);
game_state.audio_manager.play_sfx(SfxPreset::Jingle3, 1.0);
game_state.audio_manager.stop_music();
}

if win {
game_state
.audio_manager
.play_sfx(SfxPreset::Congratulations);
.play_sfx(SfxPreset::Congratulations, 1.0);
let mut you_win = game_state.add_text_actor("you win", "You Win!");
you_win.font_size = 120.0;
you_win.translation.y = -50.0;
Expand Down
4 changes: 2 additions & 2 deletions examples/scenarios/road_race.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ fn game_logic(game_state: &mut GameState) {
if *health_amount > 0 {
*health_amount -= 1;
health_message.text = format!("Health: {}", *health_amount);
game_state.audio_manager.play_sfx(SfxPreset::Impact3);
game_state.audio_manager.play_sfx(SfxPreset::Impact3, 0.5);
}
}
if *health_amount == 0 {
let game_over = game_state.add_text_actor("game over", "Game Over");
game_over.font_size = 128.0;
game_state.audio_manager.stop_music();
game_state.audio_manager.play_sfx(SfxPreset::Jingle3);
game_state.audio_manager.play_sfx(SfxPreset::Jingle3, 0.5);
}
}
4 changes: 2 additions & 2 deletions examples/sfx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ fn logic(game_state: &mut GameState) {
// None of the timers repeat, and they're all set to different times, so when the timer in
// index X goes off, play sound effect in index X
if timer.tick(game_state.delta).just_finished() {
// Play a new sound effect
// Play a new sound effect at full volume
let sfx = SfxPreset::variant_iter().nth(i).unwrap();
game_state.audio_manager.play_sfx(sfx);
game_state.audio_manager.play_sfx(sfx, 1.0);
// Update the text to show which sound effect we are playing
let sfx_label = game_state.text_actors.get_mut("sfx_label").unwrap();
sfx_label.text = format!("{:?}", sfx);
Expand Down
8 changes: 4 additions & 4 deletions scenarios/road_race.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ Now we need to actually handle the health. At **_the bottom_** of the `game_log
1. If `*health_amount` is greater than `0` (we don't want to try to subtract from an unsigned number without checking first)
1. Subtract `1` from `*health_amount`
1. Set `health_message` to the string "Health: {}", where "{}" is the value of `*health-amount`.
1. Use the `audio_manager` to play `SfxPreset::Impact3`
1. Use the `audio_manager` to play `SfxPreset::Impact3` at full volume. The value for volume ranges from `0.0` (silent) to `1.0` (full volume).
1. Try it! The game should mostly work, just with a sort of odd, frozen ending, with music still playing.

```rust
Expand All @@ -258,7 +258,7 @@ for event in game_state.collision_events.drain(..) {
if *health_amount > 0 {
*health_amount -= 1;
health_message.text = format!("Health: {}", *health_amount);
game_state.audio_manager.play_sfx(SfxPreset::Impact3);
game_state.audio_manager.play_sfx(SfxPreset::Impact3, 1.0);
}
}
```
Expand All @@ -279,15 +279,15 @@ Finally, at the very end of the `game_logic()` function we can do a bit of clean
1. Create a text actor, and set its text to `"Game Over"`
1. Using the mutable reference from creating the text actor, set its `font_size` to `128.0` (if this crashes on your system, reduce the font size to a smaller number)
1. Use the `audio_manager` to stop the music.
1. Use the `audio_manager` to play `SfxPreset::Jingle3` (it's a sad sound)
1. Use the `audio_manager` to play `SfxPreset::Jingle3` at full volume (it's a sad sound)
1. Try it!

```rust
if *health_amount == 0 {
let game_over = game_state.add_text_actor("game over", "Game Over");
game_over.font_size = 128.0;
game_state.audio_manager.stop_music();
game_state.audio_manager.play_sfx(SfxPreset::Jingle3);
game_state.audio_manager.play_sfx(SfxPreset::Jingle3, 1.0);
}
```

Expand Down
35 changes: 21 additions & 14 deletions src/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ use std::array::IntoIter;

#[derive(Debug, Default)]
pub struct AudioManager {
sfx_queue: Vec<SfxPreset>,
sfx_queue: Vec<(SfxPreset, f32)>,
music_queue: Vec<Option<(MusicPreset, f32)>>,
playing: AudioChannel,
}

impl AudioManager {
/// Play a sound
pub fn play_sfx(&mut self, sfx_preset: SfxPreset) {
self.sfx_queue.push(sfx_preset);
/// Play a sound, `volume` ranges from `0.0` to `1.0`.
pub fn play_sfx(&mut self, sfx_preset: SfxPreset, volume: f32) {
self.sfx_queue.push((sfx_preset, volume.clamp(0.0, 1.0)));
}
/// Play looping music. `volume` ranges from `0.0` to `1.0`. Any music already playing will be
/// stopped.
Expand Down Expand Up @@ -138,21 +138,28 @@ pub fn queue_managed_audio_system(
audio: Res<Audio>,
mut game_state: ResMut<GameState>,
) {
for sfx in game_state.audio_manager.sfx_queue.drain(..) {
let sfx_handle = asset_server.load(sfx.to_path());
audio.play(sfx_handle);
for (sfx_preset, volume) in game_state.audio_manager.sfx_queue.drain(..) {
let sfx_path = sfx_preset.to_path();
let sfx_handle = asset_server.load(sfx_path);
// To be able to set the volume of a sound effect, we need the channel it is being played
// in. We'll start by naively creating a new channel for every single sound effect. If this
// ends up being a performance or correctness problem, we'll need to circle back and do
// something more sophisticated (like keep a set number of channels around at different
// volumes).
let new_sfx_channel = AudioChannel::new(sfx_path.into());
audio.set_volume_in_channel(volume, &new_sfx_channel);
audio.play_in_channel(sfx_handle, &new_sfx_channel);
}
let playing = game_state.audio_manager.playing.clone();
let mut new_playing = playing.clone();
let mut playing_music = game_state.audio_manager.playing.clone();
for item in game_state.audio_manager.music_queue.drain(..) {
audio.stop_channel(&playing);
audio.stop_channel(&playing_music);
if let Some((music, volume)) = item {
let music_path = music.to_path();
let music_handle = asset_server.load(music_path);
new_playing = AudioChannel::new(music_path.into());
audio.set_volume_in_channel(volume, &new_playing);
audio.play_looped_in_channel(music_handle, &new_playing);
playing_music = AudioChannel::new(music_path.into());
audio.set_volume_in_channel(volume, &playing_music);
audio.play_looped_in_channel(music_handle, &playing_music);
}
}
game_state.audio_manager.playing = new_playing;
game_state.audio_manager.playing = playing_music;
}