diff --git a/src/systems/movement.rs b/src/systems/movement.rs index 1d398ea..f05978c 100644 --- a/src/systems/movement.rs +++ b/src/systems/movement.rs @@ -146,159 +146,3 @@ impl Position { } } } - -// pub fn movement_system( -// map: Res, -// delta_time: Res, -// mut entities: Query<(&mut Position, &mut Movable, &EntityType)>, -// mut errors: EventWriter, -// ) { -// for (mut position, mut movable, entity_type) in entities.iter_mut() { -// let distance = movable.speed * 60.0 * delta_time.0; - -// match *position { -// Position::Stopped { .. } => { -// // Check if we have a requested direction to start moving -// if let Some(requested_direction) = movable.requested_direction { -// if let Some(edge) = map.graph.find_edge_in_direction(position.current_node(), requested_direction) { -// if can_traverse(*entity_type, edge) { -// // Start moving in the requested direction -// let progress = if edge.distance > 0.0 { -// distance / edge.distance -// } else { -// // Zero-distance edge (tunnels) - immediately teleport -// tracing::debug!( -// "Entity entering tunnel from node {} to node {}", -// position.current_node(), -// edge.target -// ); -// 1.0 -// }; - -// *position = Position::Moving { -// from: position.current_node(), -// to: edge.target, -// remaining_distance: progress, -// }; -// movable.current_direction = requested_direction; -// movable.requested_direction = None; -// } -// } else { -// errors.write( -// EntityError::InvalidMovement(format!( -// "No edge found in direction {:?} from node {}", -// requested_direction, -// position.current_node() -// )) -// .into(), -// ); -// } -// } -// } -// Position::Moving { -// from, -// to, -// remaining_distance, -// } => { -// // Continue moving or handle node transitions -// let current_node = *from; -// if let Some(edge) = map.graph.find_edge(current_node, *to) { -// // Extract target node before mutable operations -// let target_node = *to; - -// // Get the current edge for distance calculation -// let edge = map.graph.find_edge(current_node, target_node); - -// if let Some(edge) = edge { -// // Update progress along the edge -// if edge.distance > 0.0 { -// *remaining_distance += distance / edge.distance; -// } else { -// // Zero-distance edge (tunnels) - immediately complete -// *remaining_distance = 1.0; -// } - -// if *remaining_distance >= 1.0 { -// // Reached the target node -// let overflow = if edge.distance > 0.0 { -// (*remaining_distance - 1.0) * edge.distance -// } else { -// // Zero-distance edge - use remaining distance for overflow -// distance -// }; -// *position = Position::Stopped { node: target_node }; - -// let mut continued_moving = false; - -// // Try to use requested direction first -// if let Some(requested_direction) = movable.requested_direction { -// if let Some(next_edge) = map.graph.find_edge_in_direction(position.node, requested_direction) { -// if can_traverse(*entity_type, next_edge) { -// let next_progress = if next_edge.distance > 0.0 { -// overflow / next_edge.distance -// } else { -// // Zero-distance edge - immediately complete -// 1.0 -// }; - -// *position = Position::Moving { -// from: position.current_node(), -// to: next_edge.target, -// remaining_distance: next_progress, -// }; -// movable.current_direction = requested_direction; -// movable.requested_direction = None; -// continued_moving = true; -// } -// } -// } - -// // If no requested direction or it failed, try to continue in current direction -// if !continued_moving { -// if let Some(next_edge) = map.graph.find_edge_in_direction(position.node, direction) { -// if can_traverse(*entity_type, next_edge) { -// let next_progress = if next_edge.distance > 0.0 { -// overflow / next_edge.distance -// } else { -// // Zero-distance edge - immediately complete -// 1.0 -// }; - -// *position = Position::Moving { -// from: position.current_node(), -// to: next_edge.target, -// remaining_distance: next_progress, -// }; -// // Keep current direction and movement state -// continued_moving = true; -// } -// } -// } - -// // If we couldn't continue moving, stop -// if !continued_moving { -// *movement_state = MovementState::Stopped; -// movable.requested_direction = None; -// } -// } -// } else { -// // Edge not found - this is an inconsistent state -// errors.write( -// EntityError::InvalidMovement(format!( -// "Inconsistent state: Moving on non-existent edge from {} to {}", -// current_node, target_node -// )) -// .into(), -// ); -// *movement_state = MovementState::Stopped; -// position.edge_progress = None; -// } -// } else { -// // Movement state says moving but no edge progress - this shouldn't happen -// errors.write(EntityError::InvalidMovement("Entity in Moving state but no edge progress".to_string()).into()); -// *movement_state = MovementState::Stopped; -// } -// } -// } -// } -// } diff --git a/src/systems/player.rs b/src/systems/player.rs index 610cc7f..eddb6b0 100644 --- a/src/systems/player.rs +++ b/src/systems/player.rs @@ -69,7 +69,7 @@ pub fn player_control_system( } } -fn can_traverse(entity_type: EntityType, edge: Edge) -> bool { +pub fn can_traverse(entity_type: EntityType, edge: Edge) -> bool { let entity_flags = entity_type.traversal_flags(); edge.traversal_flags.contains(entity_flags) } diff --git a/tests/player.rs b/tests/player.rs new file mode 100644 index 0000000..9db8404 --- /dev/null +++ b/tests/player.rs @@ -0,0 +1,100 @@ +use pacman::map::direction::Direction; +use pacman::map::graph::{Edge, TraversalFlags}; +use pacman::systems::components::EntityType; +use pacman::systems::player::can_traverse; + +#[test] +fn test_can_traverse_player_on_all_edges() { + let edge = Edge { + target: 1, + distance: 10.0, + direction: Direction::Up, + traversal_flags: TraversalFlags::ALL, + }; + + assert!(can_traverse(EntityType::Player, edge)); +} + +#[test] +fn test_can_traverse_player_on_pacman_only_edges() { + let edge = Edge { + target: 1, + distance: 10.0, + direction: Direction::Right, + traversal_flags: TraversalFlags::PACMAN, + }; + + assert!(can_traverse(EntityType::Player, edge)); +} + +#[test] +fn test_can_traverse_player_blocked_on_ghost_only_edges() { + let edge = Edge { + target: 1, + distance: 10.0, + direction: Direction::Left, + traversal_flags: TraversalFlags::GHOST, + }; + + assert!(!can_traverse(EntityType::Player, edge)); +} + +#[test] +fn test_can_traverse_ghost_on_all_edges() { + let edge = Edge { + target: 2, + distance: 15.0, + direction: Direction::Down, + traversal_flags: TraversalFlags::ALL, + }; + + assert!(can_traverse(EntityType::Ghost, edge)); +} + +#[test] +fn test_can_traverse_ghost_on_ghost_only_edges() { + let edge = Edge { + target: 2, + distance: 15.0, + direction: Direction::Up, + traversal_flags: TraversalFlags::GHOST, + }; + + assert!(can_traverse(EntityType::Ghost, edge)); +} + +#[test] +fn test_can_traverse_ghost_blocked_on_pacman_only_edges() { + let edge = Edge { + target: 2, + distance: 15.0, + direction: Direction::Right, + traversal_flags: TraversalFlags::PACMAN, + }; + + assert!(!can_traverse(EntityType::Ghost, edge)); +} + +#[test] +fn test_can_traverse_static_entities_flags() { + let edge = Edge { + target: 3, + distance: 8.0, + direction: Direction::Left, + traversal_flags: TraversalFlags::ALL, + }; + + // Static entities have empty traversal flags but can still "traverse" + // in the sense that empty flags are contained in any flag set + // This is the expected behavior since empty ⊆ any set + assert!(can_traverse(EntityType::Pellet, edge)); + assert!(can_traverse(EntityType::PowerPellet, edge)); +} + +#[test] +fn test_entity_type_traversal_flags() { + assert_eq!(EntityType::Player.traversal_flags(), TraversalFlags::PACMAN); + assert_eq!(EntityType::Ghost.traversal_flags(), TraversalFlags::GHOST); + assert_eq!(EntityType::Pellet.traversal_flags(), TraversalFlags::empty()); + assert_eq!(EntityType::PowerPellet.traversal_flags(), TraversalFlags::empty()); +}