From 6702b3723a8e5f25e8f520925c4f1e3d32d13b4c Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 11 Aug 2025 11:03:46 -0500 Subject: [PATCH] refactor: move DIRECTIONS constant into direction, add as_u8() const fn for array indexing --- src/entity/direction.rs | 24 +++++++++++++++++++++--- src/entity/pacman.rs | 36 +++++++++++++++++++++++++++++++++++- src/map/builder.rs | 6 +++--- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/entity/direction.rs b/src/entity/direction.rs index 3c2b233..bdeade8 100644 --- a/src/entity/direction.rs +++ b/src/entity/direction.rs @@ -1,5 +1,6 @@ use glam::IVec2; +/// The four cardinal directions. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Direction { Up, @@ -9,7 +10,12 @@ pub enum 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 { Direction::Up => Direction::Down, Direction::Down => Direction::Up, @@ -18,8 +24,20 @@ impl Direction { } } - pub fn as_ivec2(&self) -> IVec2 { - (*self).into() + /// Returns the direction as an IVec2. + 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, + } } } diff --git a/src/entity/pacman.rs b/src/entity/pacman.rs index 570bde3..63b84f8 100644 --- a/src/entity/pacman.rs +++ b/src/entity/pacman.rs @@ -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 crate::constants::BOARD_PIXEL_OFFSET; @@ -11,21 +17,34 @@ use sdl2::keyboard::Keycode; use sdl2::render::{Canvas, RenderTarget}; 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 { 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 { + /// Handles movement through the game graph pub traverser: Traverser, + /// Manages directional animated textures for different movement states texture: DirectionalAnimatedTexture, } 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 { let mut 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 { Direction::Up => "pacman/up", 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) { self.traverser.advance(graph, dt * 60.0 * 1.125, &can_pacman_traverse); 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) { let direction = match keycode { 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 { match self.traverser.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(&self, canvas: &mut Canvas, atlas: &mut SpriteAtlas, graph: &Graph) { 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)); diff --git a/src/map/builder.rs b/src/map/builder.rs index 9d27b83..94d9552 100644 --- a/src/map/builder.rs +++ b/src/map/builder.rs @@ -1,7 +1,7 @@ //! Map construction and building functionality. 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::map::parser::MapTileParser; 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 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(); // 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 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 graph.adjacency_list[node_id].get(dir).is_none() { let neighbor = grid_pos + dir.as_ivec2();