Add event system

This commit is contained in:
Timothy Warren 2020-07-27 09:59:14 -04:00
parent 51fd0614ce
commit 1628a5d271
7 changed files with 165 additions and 4 deletions

33
src/audio.rs Normal file
View File

@ -0,0 +1,33 @@
use ggez::{Context, audio};
use ggez::audio::SoundSource;
use specs::{World, WorldExt};
use std::collections::HashMap;
#[derive(Default)]
pub struct AudioStore {
pub sounds: HashMap<String, audio::Source>,
}
impl AudioStore {
pub fn play_sound(&mut self, sound: &String) {
let _ = self
.sounds
.get_mut(sound)
.expect("expected sound")
.play_detached();
}
}
pub fn initialize_sounds(world: &mut World, context: &mut Context) {
let mut audio_store = world.write_resource::<AudioStore>();
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 = audio::Source::new(context, sound_path).expect("expected sound loaded");
audio_store.sounds.insert(sound_name, sound_source);
}
}

23
src/events.rs Normal file
View File

@ -0,0 +1,23 @@
#[derive(Debug)]
pub enum Event {
// Fired when the player hits an obstacle like a wall
PlayerHistObstacle,
// Fired when an entity is moved
EntityMoved(EntityMoved),
// Fired when the box is placed on a spot
BoxPlacedOnSpot(BoxPlacedOnSpot),
}
pub type EntityId = u32;
#[derive(Debug)]
pub struct EntityMoved {
pub id: EntityId,
}
#[derive(Debug)]
pub struct BoxPlacedOnSpot {
pub is_correct_spot: bool,
}

View File

@ -5,13 +5,16 @@ use ggez::{conf, event, timer, Context, GameResult};
use specs::{RunNow, World, WorldExt};
use std::path;
mod audio;
mod components;
mod constants;
mod entities;
mod events;
mod map;
mod resources;
mod systems;
use crate::audio::initialize_sounds;
use crate::components::*;
use crate::map::*;
use crate::resources::*;
@ -96,6 +99,7 @@ pub fn main() -> GameResult {
.add_resource_path(path::PathBuf::from("./resources"));
let (context, event_loop) = &mut context_builder.build()?;
initialize_sounds(&mut world, context);
// Create the game state
let game = &mut Game { world };

View File

@ -4,6 +4,9 @@ use std::fmt;
use std::fmt::Display;
use std::time::Duration;
use crate::audio::AudioStore;
use crate::events::Event;
#[derive(Default)]
pub struct InputQueue {
pub keys_pressed: Vec<KeyCode>,
@ -42,8 +45,15 @@ impl Display for GameplayState {
}
}
#[derive(Default)]
pub struct EventQueue {
pub events: Vec<Event>,
}
pub fn register_resources(world: &mut World) {
world.insert(InputQueue::default());
world.insert(Gameplay::default());
world.insert(Time::default());
world.insert(EventQueue::default());
world.insert(AudioStore::default());
}

View File

@ -0,0 +1,73 @@
use specs::{Entities, Join, ReadStorage, System, Write};
use std::collections::HashMap;
use crate::{
audio::AudioStore,
components::*,
events::{BoxPlacedOnSpot, EntityMoved, Event},
resources::EventQueue,
};
pub struct EventSystem {}
impl<'a> System<'a> for EventSystem {
// Data
type SystemData = (
Write<'a, EventQueue>,
Write<'a, AudioStore>,
Entities<'a>,
ReadStorage<'a, Box>,
ReadStorage<'a, BoxSpot>,
ReadStorage<'a, Position>,
);
fn run(&mut self, data: Self::SystemData) {
let (mut event_queue, mut audio_store, entities, boxes, box_spots, positions) = data;
let mut new_events = Vec::new();
for event in event_queue.events.drain(..) {
println!("New event: {:?}", event);
match event {
Event::PlayerHistObstacle => {
// play sound here
audio_store.play_sound(&"wall".to_string());
}
Event::EntityMoved(EntityMoved { id }) => {
// 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 Some(the_box) = boxes.get(entities.entity(id)) {
let box_spots_with_positions: HashMap<(u8, u8), &BoxSpot> = (&box_spots, &positions)
.join()
.map(|t| ((t.1.x, t.1.y), t.0))
.collect();
if let Some(box_position) = positions.get(entities.entity(id)) {
// 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_with_positions.get(&(box_position.x, box_position.y)) {
new_events.push(Event::BoxPlacedOnSpot(BoxPlacedOnSpot {
is_correct_spot: (box_spot.color == the_box.color),
}));
}
}
}
}
Event::BoxPlacedOnSpot(BoxPlacedOnSpot { is_correct_spot }) => {
// play sound here
let sound = if is_correct_spot {
"correct"
} else {
"inncorrect"
};
audio_store.play_sound(&sound.to_string())
}
}
}
event_queue.events.append(&mut new_events);
}
}

View File

@ -7,13 +7,15 @@ use std::collections::HashMap;
use crate::components::*;
use crate::constants::*;
use crate::resources::{Gameplay, InputQueue};
use crate::events::{EntityMoved, Event};
use crate::resources::{EventQueue, Gameplay, InputQueue};
pub struct InputSystem {}
impl<'a> System<'a> for InputSystem {
// Data
type SystemData = (
Write<'a, EventQueue>,
Write<'a, InputQueue>,
Write<'a, Gameplay>,
Entities<'a>,
@ -24,8 +26,16 @@ impl<'a> System<'a> for InputSystem {
);
fn run(&mut self, data: Self::SystemData) {
let (mut input_queue, mut gameplay, entities, mut positions, players, movables, immovables) =
data;
let (
mut events,
mut input_queue,
mut gameplay,
entities,
mut positions,
players,
movables,
immovables,
) = data;
let mut to_move = Vec::new();
@ -76,7 +86,10 @@ impl<'a> System<'a> for InputSystem {
// if it exists, we need to stop and not move anything
// if it doesn't exist, we stop because we found a gap
match immov.get(&pos) {
Some(_) => to_move.clear(),
Some(_) => {
to_move.clear();
events.events.push(Event::PlayerHistObstacle {})
}
None => break,
}
}
@ -102,6 +115,9 @@ impl<'a> System<'a> for InputSystem {
_ => (),
}
}
// Fire an event for the entity that just moved
events.events.push(Event::EntityMoved(EntityMoved { id }));
}
}
}

View File

@ -1,7 +1,9 @@
mod event_system;
mod gameplay_state_sytem;
mod input_system;
mod rendering_system;
pub use self::event_system::EventSystem;
pub use self::gameplay_state_sytem::GameplayStateSystem;
pub use self::input_system::InputSystem;
pub use self::rendering_system::RenderingSystem;