音效

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

  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);
    }
}
}

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

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