124 lines
4.3 KiB
Rust
124 lines
4.3 KiB
Rust
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<u8> = 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 }));
|
|
}
|
|
}
|
|
}
|