音效

本节我们将添加音效。简而言之,我们希望在以下情况下播放声音:

  1. 当玩家撞击墙或障碍物时 — 提示他们无法通过
  2. 当玩家将箱子放在正确位置时 - 提示 “做对了”
  3. 当玩家将箱子放在错误位置时 - 提示 “操作错误”

音频存储

为了播放声音,需要加载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); } } }

现在运行游戏,享受这些音效吧!

代码链接: 你可以在这里查看所有代码.