Skip to content

Add ability to specify files to play as music or sound effects #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 23, 2021
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ through `EngineState:audio_manager`)
- Custom fonts may now be set on a `TextActor` at creation time.
`EngineState::add_text_actor_with_font` was added for a convenience. The font specified should be
a `.ttf` or `.otf` file stored in `assets/fonts`
- Custom sounds may now be played via `AudioManager::play_music` and `AudioManager::play_sfx` by
specifying a path to a sound file relative to `assets/audio`.

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

Expand Down
1 change: 1 addition & 0 deletions assets/audio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
You may add your own sound effects to your own local copy of this directory. Please see the `audio` module documentation for details.
46 changes: 14 additions & 32 deletions examples/music.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,26 @@
use rusty_engine::prelude::*;
//! This is an example of playing a music preset. For playing your own music file, please see the
//! `sound` example.

struct GameState {
music_index: usize,
}
use rusty_engine::prelude::*;

rusty_engine::init!(GameState);
rusty_engine::init!();

fn main() {
let mut game = Game::new();
let msg = game.add_text_actor(
"msg",
"Press any key to advance to the next music selection.\n\nIf you are not running with \"--release\", it may take several seconds for each song to load!",
"You can play looping music presets that are included in the asset pack. For example:",
);
msg.translation.y = -200.0;
msg.translation.y = 50.0;

game.add_logic(logic);
game.run(GameState { music_index: 0 });
}
let msg2 = game.add_text_actor_with_font(
"msg2",
"engine_state.audio_manager.play_music(MusicPreset::Classy8Bit, 1.0);",
"FiraMono-Medium.ttf",
);
msg2.translation.y = -50.0;

fn logic(engine_state: &mut EngineState, game_state: &mut GameState) -> bool {
let mut should_play_new_song = false;
// Play a new song because a key was pressed
for ev in engine_state.keyboard_events.drain(..) {
if ev.state != ElementState::Pressed {
continue;
}
game_state.music_index = (game_state.music_index + 1) % MusicPreset::variant_iter().count();
should_play_new_song = true;
break;
}
game.audio_manager.play_music(MusicPreset::Classy8Bit, 1.0);

if should_play_new_song || !engine_state.audio_manager.music_playing() {
// Actually play the new song
let music_preset = MusicPreset::variant_iter()
.nth(game_state.music_index)
.unwrap();
engine_state.audio_manager.play_music(music_preset, 1.0);
// And make a text actor saying what song we're playing
let note1 = engine_state.add_text_actor("note1", format!("Looping: {:?}", music_preset));
note1.font_size = 75.0;
}
true
game.run(());
}
44 changes: 44 additions & 0 deletions examples/music_sampler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use rusty_engine::prelude::*;

struct GameState {
music_index: usize,
}

rusty_engine::init!(GameState);

fn main() {
let mut game = Game::new();
let msg = game.add_text_actor(
"msg",
"Press any key to advance to the next music selection.\n\nIf you are not running with \"--release\", it may take several seconds for each song to load!",
);
msg.translation.y = -200.0;

game.add_logic(logic);
game.run(GameState { music_index: 0 });
}

fn logic(engine_state: &mut EngineState, game_state: &mut GameState) -> bool {
let mut should_play_new_song = false;
// Play a new song because a key was pressed
for ev in engine_state.keyboard_events.drain(..) {
if ev.state != ElementState::Pressed {
continue;
}
game_state.music_index = (game_state.music_index + 1) % MusicPreset::variant_iter().count();
should_play_new_song = true;
break;
}

if should_play_new_song || !engine_state.audio_manager.music_playing() {
// Actually play the new song
let music_preset = MusicPreset::variant_iter()
.nth(game_state.music_index)
.unwrap();
engine_state.audio_manager.play_music(music_preset, 1.0);
// And make a text actor saying what song we're playing
let note1 = engine_state.add_text_actor("note1", format!("Looping: {:?}", music_preset));
note1.font_size = 75.0;
}
true
}
75 changes: 20 additions & 55 deletions examples/sfx.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,26 @@
use rusty_engine::prelude::*;
//! This is an example of playing a sound effect preset. For playing your own sound effect file,
//! please see the `sound` example.

#[derive(Default)]
struct GameState {
sfx_timers: Vec<Timer>,
end_timer: Timer,
}
use rusty_engine::prelude::*;

rusty_engine::init!(GameState);
rusty_engine::init!();

fn main() {
let mut game = Game::new();
let mut game_state = GameState::default();

// One timer to launch each sound effect
for (i, _sfx) in SfxPreset::variant_iter().enumerate() {
game_state
.sfx_timers
.push(Timer::from_seconds((i as f32) * 2.0, false));
}
// One timer to end them all
game_state.end_timer =
Timer::from_seconds((SfxPreset::variant_iter().len() as f32) * 2.0 + 1.0, false);

let mut msg = game.add_text_actor("msg", "Playing sound effects!");
msg.translation = Vec2::new(0.0, 100.0);
msg.font_size = 60.0;

let mut sfx_label = game.add_text_actor("sfx_label", "");
sfx_label.translation = Vec2::new(0.0, -100.0);
sfx_label.font_size = 90.0;

game.add_logic(logic);
game.run(game_state);
}

fn logic(engine_state: &mut EngineState, game_state: &mut GameState) -> bool {
for (i, timer) in game_state.sfx_timers.iter_mut().enumerate() {
// 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(engine_state.delta).just_finished() {
// Play a new sound effect
let sfx = SfxPreset::variant_iter().nth(i).unwrap();
engine_state.audio_manager.play_sfx(sfx, 1.0);
// Update the text to show which sound effect we are playing
let sfx_label = engine_state.text_actors.get_mut("sfx_label").unwrap();
sfx_label.text = format!("{:?}", sfx);
}
}

// Are we all done?
if game_state
.end_timer
.tick(engine_state.delta)
.just_finished()
{
let sfx_label = engine_state.text_actors.get_mut("sfx_label").unwrap();
sfx_label.text = "That's all! Press Esc to quit.".into();
}
true
let msg = game.add_text_actor(
"msg",
"You can play sound effect presets that are included in the asset pack. For example:",
);
msg.translation.y = 50.0;

let msg2 = game.add_text_actor_with_font(
"msg2",
"engine_state.audio_manager.play_sfx(SfxPreset::Jingle1, 1.0);",
"FiraMono-Medium.ttf",
);
msg2.translation.y = -50.0;

game.audio_manager.play_sfx(SfxPreset::Jingle1, 1.0);

game.run(());
}
61 changes: 61 additions & 0 deletions examples/sfx_sampler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use rusty_engine::prelude::*;

#[derive(Default)]
struct GameState {
sfx_timers: Vec<Timer>,
end_timer: Timer,
}

rusty_engine::init!(GameState);

fn main() {
let mut game = Game::new();
let mut game_state = GameState::default();

// One timer to launch each sound effect
for (i, _sfx) in SfxPreset::variant_iter().enumerate() {
game_state
.sfx_timers
.push(Timer::from_seconds((i as f32) * 2.0, false));
}
// One timer to end them all
game_state.end_timer =
Timer::from_seconds((SfxPreset::variant_iter().len() as f32) * 2.0 + 1.0, false);

let mut msg = game.add_text_actor("msg", "Playing sound effects!");
msg.translation = Vec2::new(0.0, 100.0);
msg.font_size = 60.0;

let mut sfx_label = game.add_text_actor("sfx_label", "");
sfx_label.translation = Vec2::new(0.0, -100.0);
sfx_label.font_size = 90.0;

game.add_logic(logic);
game.run(game_state);
}

fn logic(engine_state: &mut EngineState, game_state: &mut GameState) -> bool {
for (i, timer) in game_state.sfx_timers.iter_mut().enumerate() {
// 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(engine_state.delta).just_finished() {
// Play a new sound effect
let sfx = SfxPreset::variant_iter().nth(i).unwrap();
engine_state.audio_manager.play_sfx(sfx, 1.0);
// Update the text to show which sound effect we are playing
let sfx_label = engine_state.text_actors.get_mut("sfx_label").unwrap();
sfx_label.text = format!("{:?}", sfx);
}
}

// Are we all done?
if game_state
.end_timer
.tick(engine_state.delta)
.just_finished()
{
let sfx_label = engine_state.text_actors.get_mut("sfx_label").unwrap();
sfx_label.text = "That's all! Press Esc to quit.".into();
}
true
}
26 changes: 26 additions & 0 deletions examples/sound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! This is an example of playing sound by path. For playing music or sound effect presets, please
//! see the `music` or `sfx` examples.

use rusty_engine::prelude::*;

rusty_engine::init!();

fn main() {
let mut game = Game::new();
let msg = game.add_text_actor(
"msg",
"You can add your own sound files to the assets/audio directory (or its\nsubdirectories) and play them by relative path. For example:",
);
msg.translation.y = 100.0;

let msg2 = game.add_text_actor_with_font(
"msg2",
"engine_state.audio_manager.play_sfx(\"sfx/congratulations.ogg\", 1.0);",
"FiraMono-Medium.ttf",
);
msg2.translation.y = -100.0;

game.audio_manager.play_sfx("sfx/congratulations.ogg", 1.0);

game.run(());
}
2 changes: 1 addition & 1 deletion src/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ impl ActorPreset {
}

/// Build a usable actor from this preset. This is called for you if you use
/// [`GameState::add_actor`].
/// [`EngineState::add_actor`](crate::prelude::EngineState::add_actor).
pub fn build(self, label: String) -> Actor {
let filename = self.filename();
let collider = self.collider();
Expand Down
Loading