mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-12 20:12:21 -06:00
refactor: move DIRECTIONS constant into direction, add as_u8() const fn for array indexing
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
use glam::IVec2;
|
use glam::IVec2;
|
||||||
|
|
||||||
|
/// The four cardinal directions.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Up,
|
Up,
|
||||||
@@ -9,7 +10,12 @@ pub enum Direction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Direction {
|
impl Direction {
|
||||||
pub fn opposite(&self) -> Direction {
|
/// The four cardinal directions.
|
||||||
|
/// This is just a convenience constant for iterating over the directions.
|
||||||
|
pub const DIRECTIONS: [Direction; 4] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right];
|
||||||
|
|
||||||
|
/// Returns the opposite direction. Constant time.
|
||||||
|
pub const fn opposite(self) -> Direction {
|
||||||
match self {
|
match self {
|
||||||
Direction::Up => Direction::Down,
|
Direction::Up => Direction::Down,
|
||||||
Direction::Down => Direction::Up,
|
Direction::Down => Direction::Up,
|
||||||
@@ -18,8 +24,20 @@ impl Direction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ivec2(&self) -> IVec2 {
|
/// Returns the direction as an IVec2.
|
||||||
(*self).into()
|
pub fn as_ivec2(self) -> IVec2 {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the direction as a u8 (0-3). Constant time.
|
||||||
|
/// This is useful for indexing into arrays.
|
||||||
|
pub const fn as_u8(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
Direction::Up => 0,
|
||||||
|
Direction::Down => 1,
|
||||||
|
Direction::Left => 2,
|
||||||
|
Direction::Right => 3,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
//! Pac-Man entity implementation.
|
||||||
|
//!
|
||||||
|
//! This module contains the main player character logic, including movement,
|
||||||
|
//! animation, and rendering. Pac-Man moves through the game graph using
|
||||||
|
//! a traverser and displays directional animated textures.
|
||||||
|
|
||||||
use glam::{UVec2, Vec2};
|
use glam::{UVec2, Vec2};
|
||||||
|
|
||||||
use crate::constants::BOARD_PIXEL_OFFSET;
|
use crate::constants::BOARD_PIXEL_OFFSET;
|
||||||
@@ -11,21 +17,34 @@ use sdl2::keyboard::Keycode;
|
|||||||
use sdl2::render::{Canvas, RenderTarget};
|
use sdl2::render::{Canvas, RenderTarget};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Determines if Pac-Man can traverse a given edge.
|
||||||
|
///
|
||||||
|
/// Pac-Man can only move through edges that allow all entities.
|
||||||
fn can_pacman_traverse(edge: Edge) -> bool {
|
fn can_pacman_traverse(edge: Edge) -> bool {
|
||||||
matches!(edge.permissions, EdgePermissions::All)
|
matches!(edge.permissions, EdgePermissions::All)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main player character entity.
|
||||||
|
///
|
||||||
|
/// Pac-Man moves through the game world using a graph-based navigation system
|
||||||
|
/// and displays directional animated sprites based on movement state.
|
||||||
pub struct Pacman {
|
pub struct Pacman {
|
||||||
|
/// Handles movement through the game graph
|
||||||
pub traverser: Traverser,
|
pub traverser: Traverser,
|
||||||
|
/// Manages directional animated textures for different movement states
|
||||||
texture: DirectionalAnimatedTexture,
|
texture: DirectionalAnimatedTexture,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pacman {
|
impl Pacman {
|
||||||
|
/// Creates a new Pac-Man instance at the specified starting node.
|
||||||
|
///
|
||||||
|
/// Sets up animated textures for all four directions with moving and stopped states.
|
||||||
|
/// The moving animation cycles through open mouth, closed mouth, and full sprites.
|
||||||
pub fn new(graph: &Graph, start_node: NodeId, atlas: &SpriteAtlas) -> Self {
|
pub fn new(graph: &Graph, start_node: NodeId, atlas: &SpriteAtlas) -> Self {
|
||||||
let mut textures = HashMap::new();
|
let mut textures = HashMap::new();
|
||||||
let mut stopped_textures = HashMap::new();
|
let mut stopped_textures = HashMap::new();
|
||||||
|
|
||||||
for &direction in &[Direction::Up, Direction::Down, Direction::Left, Direction::Right] {
|
for direction in Direction::DIRECTIONS {
|
||||||
let moving_prefix = match direction {
|
let moving_prefix = match direction {
|
||||||
Direction::Up => "pacman/up",
|
Direction::Up => "pacman/up",
|
||||||
Direction::Down => "pacman/down",
|
Direction::Down => "pacman/down",
|
||||||
@@ -56,11 +75,19 @@ impl Pacman {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates Pac-Man's position and animation state.
|
||||||
|
///
|
||||||
|
/// Advances movement through the graph and updates texture animation.
|
||||||
|
/// Movement speed is scaled by 60 FPS and a 1.125 multiplier.
|
||||||
pub fn tick(&mut self, dt: f32, graph: &Graph) {
|
pub fn tick(&mut self, dt: f32, graph: &Graph) {
|
||||||
self.traverser.advance(graph, dt * 60.0 * 1.125, &can_pacman_traverse);
|
self.traverser.advance(graph, dt * 60.0 * 1.125, &can_pacman_traverse);
|
||||||
self.texture.tick(dt);
|
self.texture.tick(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles keyboard input to change Pac-Man's direction.
|
||||||
|
///
|
||||||
|
/// Maps arrow keys to directions and queues the direction change
|
||||||
|
/// for the next valid intersection.
|
||||||
pub fn handle_key(&mut self, keycode: Keycode) {
|
pub fn handle_key(&mut self, keycode: Keycode) {
|
||||||
let direction = match keycode {
|
let direction = match keycode {
|
||||||
Keycode::Up => Some(Direction::Up),
|
Keycode::Up => Some(Direction::Up),
|
||||||
@@ -75,6 +102,9 @@ impl Pacman {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the current pixel position in the game world.
|
||||||
|
///
|
||||||
|
/// Interpolates between nodes when moving between them.
|
||||||
fn get_pixel_pos(&self, graph: &Graph) -> Vec2 {
|
fn get_pixel_pos(&self, graph: &Graph) -> Vec2 {
|
||||||
match self.traverser.position {
|
match self.traverser.position {
|
||||||
Position::AtNode(node_id) => graph.get_node(node_id).unwrap().position,
|
Position::AtNode(node_id) => graph.get_node(node_id).unwrap().position,
|
||||||
@@ -86,6 +116,10 @@ impl Pacman {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Renders Pac-Man to the canvas.
|
||||||
|
///
|
||||||
|
/// Calculates screen position, determines if Pac-Man is stopped,
|
||||||
|
/// and renders the appropriate directional texture.
|
||||||
pub fn render<T: RenderTarget>(&self, canvas: &mut Canvas<T>, atlas: &mut SpriteAtlas, graph: &Graph) {
|
pub fn render<T: RenderTarget>(&self, canvas: &mut Canvas<T>, atlas: &mut SpriteAtlas, graph: &Graph) {
|
||||||
let pixel_pos = self.get_pixel_pos(graph).round().as_ivec2() + BOARD_PIXEL_OFFSET.as_ivec2();
|
let pixel_pos = self.get_pixel_pos(graph).round().as_ivec2() + BOARD_PIXEL_OFFSET.as_ivec2();
|
||||||
let dest = centered_with_size(pixel_pos, UVec2::new(16, 16));
|
let dest = centered_with_size(pixel_pos, UVec2::new(16, 16));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Map construction and building functionality.
|
//! Map construction and building functionality.
|
||||||
|
|
||||||
use crate::constants::{MapTile, BOARD_CELL_SIZE, CELL_SIZE};
|
use crate::constants::{MapTile, BOARD_CELL_SIZE, CELL_SIZE};
|
||||||
use crate::entity::direction::{Direction, DIRECTIONS};
|
use crate::entity::direction::Direction;
|
||||||
use crate::entity::graph::{EdgePermissions, Graph, Node, NodeId};
|
use crate::entity::graph::{EdgePermissions, Graph, Node, NodeId};
|
||||||
use crate::map::parser::MapTileParser;
|
use crate::map::parser::MapTileParser;
|
||||||
use crate::map::render::MapRenderer;
|
use crate::map::render::MapRenderer;
|
||||||
@@ -75,7 +75,7 @@ impl Map {
|
|||||||
|
|
||||||
// Iterate over the queue, adding nodes to the graph and connecting them to their neighbors
|
// Iterate over the queue, adding nodes to the graph and connecting them to their neighbors
|
||||||
while let Some(source_position) = queue.pop_front() {
|
while let Some(source_position) = queue.pop_front() {
|
||||||
for &dir in DIRECTIONS.iter() {
|
for dir in Direction::DIRECTIONS {
|
||||||
let new_position = source_position + dir.as_ivec2();
|
let new_position = source_position + dir.as_ivec2();
|
||||||
|
|
||||||
// Skip if the new position is out of bounds
|
// Skip if the new position is out of bounds
|
||||||
@@ -121,7 +121,7 @@ impl Map {
|
|||||||
|
|
||||||
// While most nodes are already connected to their neighbors, some may not be, so we need to connect them
|
// While most nodes are already connected to their neighbors, some may not be, so we need to connect them
|
||||||
for (grid_pos, &node_id) in &grid_to_node {
|
for (grid_pos, &node_id) in &grid_to_node {
|
||||||
for dir in DIRECTIONS {
|
for dir in Direction::DIRECTIONS {
|
||||||
// If the node doesn't have an edge in this direction, look for a neighbor in that direction
|
// If the node doesn't have an edge in this direction, look for a neighbor in that direction
|
||||||
if graph.adjacency_list[node_id].get(dir).is_none() {
|
if graph.adjacency_list[node_id].get(dir).is_none() {
|
||||||
let neighbor = grid_pos + dir.as_ivec2();
|
let neighbor = grid_pos + dir.as_ivec2();
|
||||||
|
|||||||
Reference in New Issue
Block a user