diff --git a/src/systems/ghost.rs b/src/systems/ghost.rs index e477d27..bd96b17 100644 --- a/src/systems/ghost.rs +++ b/src/systems/ghost.rs @@ -18,9 +18,9 @@ use crate::{ pub fn ghost_movement_system( map: Res, delta_time: Res, - mut ghosts: Query<(&mut Ghost, &mut Velocity, &mut Position)>, + mut ghosts: Query<(&Ghost, &mut Velocity, &mut Position)>, ) { - for (mut ghost, mut velocity, mut position) in ghosts.iter_mut() { + for (_ghost, mut velocity, mut position) in ghosts.iter_mut() { let mut distance = velocity.speed * 60.0 * delta_time.0; loop { match *position { @@ -32,10 +32,10 @@ pub fn ghost_movement_system( // Collect all available directions that ghosts can traverse for edge in Direction::DIRECTIONS.iter().flat_map(|d| intersection.get(*d)) { - if edge.traversal_flags.contains(crate::entity::graph::TraversalFlags::GHOST) { - if edge.direction != opposite { - non_opposite_options.push(edge); - } + if edge.traversal_flags.contains(crate::entity::graph::TraversalFlags::GHOST) + && edge.direction != opposite + { + non_opposite_options.push(edge); } } @@ -67,39 +67,3 @@ pub fn ghost_movement_system( } } } - -/// Chooses a random available direction for a ghost at an intersection. -/// -/// This function mirrors the behavior from the old ghost implementation, -/// preferring not to reverse direction unless it's the only option. -fn choose_random_direction(map: &Map, velocity: &mut Velocity, position: &Position) { - let current_node = position.current_node(); - let intersection = &map.graph.adjacency_list[current_node]; - - // Collect all available directions that ghosts can traverse - let mut available_directions = SmallVec::<[Direction; 4]>::new(); - for direction in Direction::DIRECTIONS { - if let Some(edge) = intersection.get(direction) { - // Check if ghosts can traverse this edge - if edge.traversal_flags.contains(crate::entity::graph::TraversalFlags::GHOST) { - available_directions.push(direction); - } - } - } - - // Choose a random direction (avoid reversing unless necessary) - if !available_directions.is_empty() { - let mut rng = SmallRng::from_os_rng(); - - // Filter out the opposite direction if possible, but allow it if we have limited options - let opposite = velocity.direction.opposite(); - let filtered_directions: Vec<_> = available_directions - .iter() - .filter(|&&dir| dir != opposite || available_directions.len() <= 2) - .collect(); - - if let Some(&random_direction) = filtered_directions.choose(&mut rng) { - velocity.direction = *random_direction; - } - } -} diff --git a/src/systems/input.rs b/src/systems/input.rs index ab62cce..0620539 100644 --- a/src/systems/input.rs +++ b/src/systems/input.rs @@ -1,6 +1,10 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; -use bevy_ecs::{event::EventWriter, prelude::Res, resource::Resource, system::NonSendMut}; +use bevy_ecs::{ + event::EventWriter, + resource::Resource, + system::{NonSendMut, ResMut}, +}; use sdl2::{event::Event, keyboard::Keycode, EventPump}; use crate::{ @@ -11,6 +15,8 @@ use crate::{ #[derive(Debug, Clone, Resource)] pub struct Bindings { key_bindings: HashMap, + movement_keys: HashSet, + last_movement_key: Option, } impl Default for Bindings { @@ -35,23 +41,74 @@ impl Default for Bindings { key_bindings.insert(Keycode::Escape, GameCommand::Exit); key_bindings.insert(Keycode::Q, GameCommand::Exit); - Self { key_bindings } + let movement_keys = HashSet::from([ + Keycode::W, + Keycode::A, + Keycode::S, + Keycode::D, + Keycode::Up, + Keycode::Down, + Keycode::Left, + Keycode::Right, + ]); + + Self { + key_bindings, + movement_keys, + last_movement_key: None, + } } } -pub fn input_system(bindings: Res, mut writer: EventWriter, mut pump: NonSendMut<&'static mut EventPump>) { +pub fn input_system( + mut bindings: ResMut, + mut writer: EventWriter, + mut pump: NonSendMut<&'static mut EventPump>, +) { + let mut movement_key_pressed = false; + for event in pump.poll_iter() { match event { Event::Quit { .. } => { writer.write(GameEvent::Command(GameCommand::Exit)); } - Event::KeyDown { keycode: Some(key), .. } => { + Event::KeyUp { + repeat: false, + keycode: Some(key), + .. + } => { + // If the last movement key was released, then forget it. + if let Some(last_movement_key) = bindings.last_movement_key { + if last_movement_key == key { + bindings.last_movement_key = None; + } + } + } + Event::KeyDown { + keycode: Some(key), + repeat: false, + .. + } => { let command = bindings.key_bindings.get(&key).copied(); if let Some(command) = command { writer.write(GameEvent::Command(command)); } + + if bindings.movement_keys.contains(&key) { + movement_key_pressed = true; + bindings.last_movement_key = Some(key); + } } _ => {} } } + + if let Some(last_movement_key) = bindings.last_movement_key { + if !movement_key_pressed { + let command = bindings.key_bindings.get(&last_movement_key).copied(); + if let Some(command) = command { + writer.write(GameEvent::Command(command)); + } + } + } } diff --git a/src/systems/movement.rs b/src/systems/movement.rs index ae34c28..0b9c522 100644 --- a/src/systems/movement.rs +++ b/src/systems/movement.rs @@ -1,12 +1,7 @@ +use crate::entity::direction::Direction; use crate::entity::graph::Graph; -use crate::entity::{direction::Direction, graph::Edge}; -use crate::error::{EntityError, GameError, GameResult}; -use crate::map::builder::Map; -use crate::systems::components::{DeltaTime, EntityType, PlayerControlled}; +use crate::error::{EntityError, GameResult}; use bevy_ecs::component::Component; -use bevy_ecs::event::EventWriter; -use bevy_ecs::query::With; -use bevy_ecs::system::{Query, Res}; use glam::Vec2; /// A unique identifier for a node, represented by its index in the graph's storage. diff --git a/src/systems/player.rs b/src/systems/player.rs index 2f6b758..6673c4a 100644 --- a/src/systems/player.rs +++ b/src/systems/player.rs @@ -23,7 +23,7 @@ pub fn player_control_system( mut state: ResMut, mut debug_state: ResMut, mut audio_state: ResMut, - mut players: Query<(&mut BufferedDirection), With>, + mut players: Query<&mut BufferedDirection, With>, mut errors: EventWriter, ) { // Get the player's movable component (ensuring there is only one player) @@ -73,7 +73,7 @@ pub fn player_movement_system( map: Res, delta_time: Res, mut entities: Query<(&mut Position, &mut Velocity, &mut BufferedDirection), With>, - mut errors: EventWriter, + // mut errors: EventWriter, ) { for (mut position, mut velocity, mut buffered_direction) in entities.iter_mut() { // Decrement the buffered direction remaining time