use ggez::event::KeyCode; use specs::join::Join; use specs::world::Index; use specs::{Entities, ReadStorage, System, Write, WriteStorage}; use std::collections::HashMap; use crate::components::*; use crate::constants::*; 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>, WriteStorage<'a, Position>, ReadStorage<'a, Player>, ReadStorage<'a, Movable>, ReadStorage<'a, Immovable>, ); fn run(&mut self, data: Self::SystemData) { let ( mut events, mut input_queue, mut gameplay, entities, mut positions, players, movables, immovables, ) = data; let mut to_move = Vec::new(); for (position, _player) in (&positions, &players).join() { // Get the first key pressed if let Some(key) = input_queue.keys_pressed.pop() { // get all the movables and immovables type MovMap = HashMap<(u8, u8), Index>; let mov: MovMap = (&entities, &movables, &positions) .join() .map(|t| ((t.2.x, t.2.y), t.0.id())) .collect(); let immov: MovMap = (&entities, &immovables, &positions) .join() .map(|t| ((t.2.x, t.2.y), t.0.id())) .collect(); // Now iterate through current position to the end of the map // on the correct axis and check what needs to move. let (start, end, is_x) = match key { KeyCode::Up => (position.y, 0, false), KeyCode::Down => (position.y, MAP_HEIGHT, false), KeyCode::Left => (position.x, 0, true), KeyCode::Right => (position.x, MAP_WIDTH, true), _ => continue, }; let range: Vec = if start < end { (start..=end).collect() } else { (end..=start).rev().collect() }; for value in range { let pos = if is_x { (value, position.y) } else { (position.x, value) }; // find a movable // if it exists, we try to move it and continue // if it doesn't exist, we continue and try to find an immovable instead match mov.get(&pos) { Some(id) => to_move.push((key, *id)), None => { // find an immovable // 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(); events.events.push(Event::PlayerHistObstacle {}) } None => break, } } } } } } // We've just moved, so let's increase the number of moves if to_move.len() > 0 { gameplay.moves_count += 1; } // Now actually move what needs to be moved for (key, id) in to_move { let position = positions.get_mut(entities.entity(id)); if let Some(position) = position { match key { KeyCode::Up => position.y -= 1, KeyCode::Down => position.y += 1, KeyCode::Left => position.x -= 1, KeyCode::Right => position.x += 1, _ => (), } } // Fire an event for the entity that just moved events.events.push(Event::EntityMoved(EntityMoved { id })); } } }