mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-06 05:15:49 -06:00
fix: allow key holddown
This commit is contained in:
@@ -18,9 +18,9 @@ use crate::{
|
|||||||
pub fn ghost_movement_system(
|
pub fn ghost_movement_system(
|
||||||
map: Res<Map>,
|
map: Res<Map>,
|
||||||
delta_time: Res<DeltaTime>,
|
delta_time: Res<DeltaTime>,
|
||||||
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;
|
let mut distance = velocity.speed * 60.0 * delta_time.0;
|
||||||
loop {
|
loop {
|
||||||
match *position {
|
match *position {
|
||||||
@@ -32,10 +32,10 @@ pub fn ghost_movement_system(
|
|||||||
|
|
||||||
// Collect all available directions that ghosts can traverse
|
// Collect all available directions that ghosts can traverse
|
||||||
for edge in Direction::DIRECTIONS.iter().flat_map(|d| intersection.get(*d)) {
|
for edge in Direction::DIRECTIONS.iter().flat_map(|d| intersection.get(*d)) {
|
||||||
if edge.traversal_flags.contains(crate::entity::graph::TraversalFlags::GHOST) {
|
if edge.traversal_flags.contains(crate::entity::graph::TraversalFlags::GHOST)
|
||||||
if edge.direction != opposite {
|
&& edge.direction != opposite
|
||||||
non_opposite_options.push(edge);
|
{
|
||||||
}
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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 sdl2::{event::Event, keyboard::Keycode, EventPump};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -11,6 +15,8 @@ use crate::{
|
|||||||
#[derive(Debug, Clone, Resource)]
|
#[derive(Debug, Clone, Resource)]
|
||||||
pub struct Bindings {
|
pub struct Bindings {
|
||||||
key_bindings: HashMap<Keycode, GameCommand>,
|
key_bindings: HashMap<Keycode, GameCommand>,
|
||||||
|
movement_keys: HashSet<Keycode>,
|
||||||
|
last_movement_key: Option<Keycode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Bindings {
|
impl Default for Bindings {
|
||||||
@@ -35,23 +41,74 @@ impl Default for Bindings {
|
|||||||
key_bindings.insert(Keycode::Escape, GameCommand::Exit);
|
key_bindings.insert(Keycode::Escape, GameCommand::Exit);
|
||||||
key_bindings.insert(Keycode::Q, 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<Bindings>, mut writer: EventWriter<GameEvent>, mut pump: NonSendMut<&'static mut EventPump>) {
|
pub fn input_system(
|
||||||
|
mut bindings: ResMut<Bindings>,
|
||||||
|
mut writer: EventWriter<GameEvent>,
|
||||||
|
mut pump: NonSendMut<&'static mut EventPump>,
|
||||||
|
) {
|
||||||
|
let mut movement_key_pressed = false;
|
||||||
|
|
||||||
for event in pump.poll_iter() {
|
for event in pump.poll_iter() {
|
||||||
match event {
|
match event {
|
||||||
Event::Quit { .. } => {
|
Event::Quit { .. } => {
|
||||||
writer.write(GameEvent::Command(GameCommand::Exit));
|
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();
|
let command = bindings.key_bindings.get(&key).copied();
|
||||||
if let Some(command) = command {
|
if let Some(command) = command {
|
||||||
writer.write(GameEvent::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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
|
use crate::entity::direction::Direction;
|
||||||
use crate::entity::graph::Graph;
|
use crate::entity::graph::Graph;
|
||||||
use crate::entity::{direction::Direction, graph::Edge};
|
use crate::error::{EntityError, GameResult};
|
||||||
use crate::error::{EntityError, GameError, GameResult};
|
|
||||||
use crate::map::builder::Map;
|
|
||||||
use crate::systems::components::{DeltaTime, EntityType, PlayerControlled};
|
|
||||||
use bevy_ecs::component::Component;
|
use bevy_ecs::component::Component;
|
||||||
use bevy_ecs::event::EventWriter;
|
|
||||||
use bevy_ecs::query::With;
|
|
||||||
use bevy_ecs::system::{Query, Res};
|
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
|
|
||||||
/// A unique identifier for a node, represented by its index in the graph's storage.
|
/// A unique identifier for a node, represented by its index in the graph's storage.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub fn player_control_system(
|
|||||||
mut state: ResMut<GlobalState>,
|
mut state: ResMut<GlobalState>,
|
||||||
mut debug_state: ResMut<DebugState>,
|
mut debug_state: ResMut<DebugState>,
|
||||||
mut audio_state: ResMut<AudioState>,
|
mut audio_state: ResMut<AudioState>,
|
||||||
mut players: Query<(&mut BufferedDirection), With<PlayerControlled>>,
|
mut players: Query<&mut BufferedDirection, With<PlayerControlled>>,
|
||||||
mut errors: EventWriter<GameError>,
|
mut errors: EventWriter<GameError>,
|
||||||
) {
|
) {
|
||||||
// Get the player's movable component (ensuring there is only one player)
|
// Get the player's movable component (ensuring there is only one player)
|
||||||
@@ -73,7 +73,7 @@ pub fn player_movement_system(
|
|||||||
map: Res<Map>,
|
map: Res<Map>,
|
||||||
delta_time: Res<DeltaTime>,
|
delta_time: Res<DeltaTime>,
|
||||||
mut entities: Query<(&mut Position, &mut Velocity, &mut BufferedDirection), With<PlayerControlled>>,
|
mut entities: Query<(&mut Position, &mut Velocity, &mut BufferedDirection), With<PlayerControlled>>,
|
||||||
mut errors: EventWriter<GameError>,
|
// mut errors: EventWriter<GameError>,
|
||||||
) {
|
) {
|
||||||
for (mut position, mut velocity, mut buffered_direction) in entities.iter_mut() {
|
for (mut position, mut velocity, mut buffered_direction) in entities.iter_mut() {
|
||||||
// Decrement the buffered direction remaining time
|
// Decrement the buffered direction remaining time
|
||||||
|
|||||||
Reference in New Issue
Block a user