音效
本节我们将添加音效。简而言之,我们希望在以下情况下播放声音:
- 当玩家撞击墙或障碍物时 — 提示他们无法通过
- 当玩家将箱子放在正确位置时 - 提示 “做对了”
- 当玩家将箱子放在错误位置时 - 提示 “操作错误”
音频存储
为了播放声音,需要加载wav文件。为了避免每次播放前临时加载,我们将创建一个音频存储,并在游戏开始时预先加载它们。
我们可以使用一个资源来定义音频存储。
#![allow(unused)]
fn main() {
#[derive(Default)]
pub struct AudioStore {
pub sounds: HashMap<String, std::boxed::Box<audio::Source>>,
}
}
接下来添加初始化存储的代码,也就是预加载游戏所需的所有音效。
#![allow(unused)]
fn main() {
pub fn load_sounds(world: &mut World, context: &mut Context) {
let mut query = world.query::<&mut crate::components::AudioStore>();
let audio_store = query.iter().next().unwrap().1;
let sounds = ["correct", "incorrect", "wall"];
for sound in sounds.iter() {
let sound_name = sound.to_string();
let sound_path = format!("/sounds/{}.wav", sound_name);
let sound_source = Source::new(context, sound_path).expect("expected sound loaded");
audio_store
.sounds
.insert(sound_name, Box::new(sound_source));
}
}
}
然后在初始化关卡时调用这个函数。
#![allow(unused)]
fn main() {
pub fn initialize_level(world: &mut World, context: &mut Context) {
const MAP: &str = "
N N W W W W W W
W W W . . . . W
W . . . BB . . W
W . . RB . . . W
W . P . . . . W
W . . . . RS . W
W . . BS . . . W
W . . . . . . W
W W W W W W W W
";
load_map(world, MAP.to_string());
load_sounds(world, context);
}
}
播放声音
最后, 我们需要在 audio store 中添加声音播放的代码。
#![allow(unused)]
fn main() {
impl AudioStore {
pub fn play_sound(&mut self, context: &mut Context, sound: &str) {
if let Some(source) = self.sounds.get_mut(sound) {
if source.play_detached(context).is_ok() {
println!("Playing sound: {}", sound);
}
}
}
}
}
现在在事件系统中播放音效:
#![allow(unused)]
fn main() {
// systems/events.rs
use crate::components::*;
use crate::events::*;
use ggez::Context;
use hecs::World;
use std::collections::HashMap;
pub fn run_process_events(world: &mut World, context: &mut Context) {
let events = {
let mut query = world.query::<&mut crate::components::EventQueue>();
let events = query
.iter()
.next()
.unwrap()
.1
.events
.drain(..)
.collect::<Vec<_>>();
events
};
let mut new_events = Vec::new();
let mut query = world.query::<(&Position, &BoxSpot)>();
let box_spots_by_position: HashMap<(u8, u8), &BoxSpot> = query
.iter()
.map(|(_, t)| ((t.0.x, t.0.y), t.1))
.collect::<HashMap<_, _>>();
let mut query = world.query::<&mut AudioStore>();
let audio_store = query.iter().next().unwrap().1;
for event in events {
println!("New event: {:?}", event);
match event {
Event::PlayerHitObstacle => {
// play sound here
audio_store.play_sound(context, "wall");
}
Event::EntityMoved(EntityMoved { entity }) => {
// An entity was just moved, check if it was a box and fire
// more events if it's been moved on a spot.
if let Ok(the_box) = world.get::<&Box>(entity) {
if let Ok(box_position) = world.get::<&Position>(entity) {
// Check if there is a spot on this position, and if there
// is if it's the correct or incorrect type
if let Some(box_spot) =
box_spots_by_position.get(&(box_position.x, box_position.y))
{
new_events.push(Event::BoxPlacedOnSpot(BoxPlacedOnSpot {
is_correct_spot: (box_spot.colour == the_box.colour),
}));
}
}
}
}
Event::BoxPlacedOnSpot(BoxPlacedOnSpot { is_correct_spot }) => {
// play sound here
let sound = if is_correct_spot {
"correct"
} else {
"incorrect"
};
audio_store.play_sound(context, sound);
}
}
}
// Finally add events back into the world
{
let mut query = world.query::<&mut EventQueue>();
let event_queue = query.iter().next().unwrap().1;
event_queue.events.append(&mut new_events);
}
}
}
现在运行游戏,享受这些音效吧!
代码链接: 你可以在这里查看所有代码.