mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-06 09:15:46 -06:00
refactor: static intersection struct for calculating edges instead of smallvec
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -192,7 +192,6 @@ dependencies = [
|
|||||||
"sdl2",
|
"sdl2",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"smallvec",
|
|
||||||
"spin_sleep",
|
"spin_sleep",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ anyhow = "1.0"
|
|||||||
glam = { version = "0.30.4", features = [] }
|
glam = { version = "0.30.4", features = [] }
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
serde_json = "1.0.141"
|
serde_json = "1.0.141"
|
||||||
smallvec = "1.15.1"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use smallvec::SmallVec;
|
|
||||||
|
|
||||||
use super::direction::Direction;
|
use super::direction::Direction;
|
||||||
|
|
||||||
@@ -9,21 +8,88 @@ pub type NodeId = usize;
|
|||||||
/// Represents a directed edge from one node to another with a given weight (e.g., distance).
|
/// Represents a directed edge from one node to another with a given weight (e.g., distance).
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Edge {
|
pub struct Edge {
|
||||||
|
/// The destination node of this edge.
|
||||||
pub target: NodeId,
|
pub target: NodeId,
|
||||||
|
/// The length of the edge.
|
||||||
pub distance: f32,
|
pub distance: f32,
|
||||||
|
/// The cardinal direction of this edge.
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a node in the graph, defined by its position.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
|
/// The 2D coordinates of the node.
|
||||||
pub position: Vec2,
|
pub position: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A generic, arena-based graph.
|
/// Represents the four possible directions from a node in the graph.
|
||||||
/// The graph owns all node data and connection information.
|
///
|
||||||
|
/// Each field contains an optional edge leading in that direction.
|
||||||
|
/// This structure is used to represent the adjacency list for each node,
|
||||||
|
/// providing O(1) access to edges in any cardinal direction.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Intersection {
|
||||||
|
/// Edge leading upward from this node, if it exists.
|
||||||
|
pub up: Option<Edge>,
|
||||||
|
/// Edge leading downward from this node, if it exists.
|
||||||
|
pub down: Option<Edge>,
|
||||||
|
/// Edge leading leftward from this node, if it exists.
|
||||||
|
pub left: Option<Edge>,
|
||||||
|
/// Edge leading rightward from this node, if it exists.
|
||||||
|
pub right: Option<Edge>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Intersection {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
up: None,
|
||||||
|
down: None,
|
||||||
|
left: None,
|
||||||
|
right: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Intersection {
|
||||||
|
/// Returns an iterator over all edges from this intersection.
|
||||||
|
///
|
||||||
|
/// This iterator yields only the edges that exist (non-None values).
|
||||||
|
pub fn edges(&self) -> impl Iterator<Item = Edge> {
|
||||||
|
[self.up, self.down, self.left, self.right].into_iter().flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the edge in the specified direction, if it exists.
|
||||||
|
pub fn get(&self, direction: Direction) -> Option<Edge> {
|
||||||
|
match direction {
|
||||||
|
Direction::Up => self.up,
|
||||||
|
Direction::Down => self.down,
|
||||||
|
Direction::Left => self.left,
|
||||||
|
Direction::Right => self.right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the edge in the specified direction.
|
||||||
|
///
|
||||||
|
/// This will overwrite any existing edge in that direction.
|
||||||
|
pub fn set(&mut self, direction: Direction, edge: Edge) {
|
||||||
|
match direction {
|
||||||
|
Direction::Up => self.up = Some(edge),
|
||||||
|
Direction::Down => self.down = Some(edge),
|
||||||
|
Direction::Left => self.left = Some(edge),
|
||||||
|
Direction::Right => self.right = Some(edge),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A directed graph structure using an adjacency list representation.
|
||||||
|
///
|
||||||
|
/// Nodes are stored in a vector, and their indices serve as their `NodeId`.
|
||||||
|
/// This design provides fast, O(1) lookups for node data. Edges are stored
|
||||||
|
/// in an adjacency list, where each node has a list of outgoing edges.
|
||||||
pub struct Graph {
|
pub struct Graph {
|
||||||
nodes: Vec<Node>,
|
nodes: Vec<Node>,
|
||||||
adjacency_list: Vec<SmallVec<[Edge; 4]>>,
|
adjacency_list: Vec<Intersection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Graph {
|
impl Graph {
|
||||||
@@ -39,11 +105,22 @@ impl Graph {
|
|||||||
pub fn add_node(&mut self, data: Node) -> NodeId {
|
pub fn add_node(&mut self, data: Node) -> NodeId {
|
||||||
let id = self.nodes.len();
|
let id = self.nodes.len();
|
||||||
self.nodes.push(data);
|
self.nodes.push(data);
|
||||||
self.adjacency_list.push(SmallVec::new());
|
self.adjacency_list.push(Intersection::default());
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a directed edge between two nodes.
|
/// Adds a directed edge between two nodes.
|
||||||
|
///
|
||||||
|
/// If `distance` is `None`, it will be calculated automatically based on the
|
||||||
|
/// Euclidean distance between the two nodes.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if:
|
||||||
|
/// - The `from` node does not exist
|
||||||
|
/// - An edge already exists in the specified direction
|
||||||
|
/// - An edge already exists to the target node
|
||||||
|
/// - The provided distance is not positive
|
||||||
pub fn add_edge(
|
pub fn add_edge(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: NodeId,
|
from: NodeId,
|
||||||
@@ -77,7 +154,7 @@ impl Graph {
|
|||||||
let adjacency_list = &mut self.adjacency_list[from];
|
let adjacency_list = &mut self.adjacency_list[from];
|
||||||
|
|
||||||
// Check if the edge already exists in this direction or to the same target
|
// Check if the edge already exists in this direction or to the same target
|
||||||
if let Some(err) = adjacency_list.iter().find_map(|e| {
|
if let Some(err) = adjacency_list.edges().find_map(|e| {
|
||||||
if e.direction == direction {
|
if e.direction == direction {
|
||||||
Some(Err("Edge already exists in this direction."))
|
Some(Err("Edge already exists in this direction."))
|
||||||
} else if e.target == to {
|
} else if e.target == to {
|
||||||
@@ -89,7 +166,7 @@ impl Graph {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
adjacency_list.push(edge);
|
adjacency_list.set(direction, edge);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -99,17 +176,19 @@ impl Graph {
|
|||||||
self.nodes.get(id)
|
self.nodes.get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the total number of nodes in the graph.
|
||||||
pub fn node_count(&self) -> usize {
|
pub fn node_count(&self) -> usize {
|
||||||
self.nodes.len()
|
self.nodes.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds a specific edge from a source node to a target node.
|
/// Finds a specific edge from a source node to a target node.
|
||||||
pub fn find_edge(&self, from: NodeId, to: NodeId) -> Option<&Edge> {
|
pub fn find_edge(&self, from: NodeId, to: NodeId) -> Option<Edge> {
|
||||||
self.adjacency_list.get(from)?.iter().find(|edge| edge.target == to)
|
self.adjacency_list.get(from)?.edges().find(|edge| edge.target == to)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_edge_in_direction(&self, from: NodeId, direction: Direction) -> Option<&Edge> {
|
/// Finds an edge originating from a given node that follows a specific direction.
|
||||||
self.adjacency_list.get(from)?.iter().find(|edge| edge.direction == direction)
|
pub fn find_edge_in_direction(&self, from: NodeId, direction: Direction) -> Option<Edge> {
|
||||||
|
self.adjacency_list.get(from)?.get(direction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +201,10 @@ impl Default for Graph {
|
|||||||
|
|
||||||
// --- Traversal State and Logic ---
|
// --- Traversal State and Logic ---
|
||||||
|
|
||||||
/// Represents the traverser's current position within the graph.
|
/// Represents the current position of an entity traversing the graph.
|
||||||
|
///
|
||||||
|
/// This enum allows for precise tracking of whether an entity is exactly at a node
|
||||||
|
/// or moving along an edge between two nodes.
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum Position {
|
pub enum Position {
|
||||||
/// The traverser is located exactly at a node.
|
/// The traverser is located exactly at a node.
|
||||||
@@ -137,10 +219,12 @@ pub enum Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
|
/// Returns `true` if the position is exactly at a node.
|
||||||
pub fn is_at_node(&self) -> bool {
|
pub fn is_at_node(&self) -> bool {
|
||||||
matches!(self, Position::AtNode(_))
|
matches!(self, Position::AtNode(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `NodeId` of the current or most recently departed node.
|
||||||
pub fn from_node_id(&self) -> NodeId {
|
pub fn from_node_id(&self) -> NodeId {
|
||||||
match self {
|
match self {
|
||||||
Position::AtNode(id) => *id,
|
Position::AtNode(id) => *id,
|
||||||
@@ -148,6 +232,7 @@ impl Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `NodeId` of the destination node, if currently on an edge.
|
||||||
pub fn to_node_id(&self) -> Option<NodeId> {
|
pub fn to_node_id(&self) -> Option<NodeId> {
|
||||||
match self {
|
match self {
|
||||||
Position::AtNode(_) => None,
|
Position::AtNode(_) => None,
|
||||||
@@ -155,21 +240,34 @@ impl Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the traverser is stopped at a node.
|
||||||
pub fn is_stopped(&self) -> bool {
|
pub fn is_stopped(&self) -> bool {
|
||||||
matches!(self, Position::AtNode(_))
|
matches!(self, Position::AtNode(_))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manages a traversal session over a graph.
|
/// Manages an entity's movement through the graph.
|
||||||
/// It holds a reference to the graph and the current position state.
|
///
|
||||||
|
/// A `Traverser` encapsulates the state of an entity's position and direction,
|
||||||
|
/// providing a way to advance along the graph's paths based on a given distance.
|
||||||
|
/// It also handles direction changes, buffering the next intended direction.
|
||||||
pub struct Traverser {
|
pub struct Traverser {
|
||||||
|
/// The current position of the traverser in the graph.
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
|
/// The current direction of movement.
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
|
/// Buffered direction change with remaining frame count for timing.
|
||||||
|
///
|
||||||
|
/// The `u8` value represents the number of frames remaining before
|
||||||
|
/// the buffered direction expires. This allows for responsive controls
|
||||||
|
/// by storing direction changes for a limited time.
|
||||||
pub next_direction: Option<(Direction, u8)>,
|
pub next_direction: Option<(Direction, u8)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Traverser {
|
impl Traverser {
|
||||||
/// Creates a new traverser starting at the given node ID.
|
/// Creates a new traverser starting at the given node ID.
|
||||||
|
///
|
||||||
|
/// The traverser will immediately attempt to start moving in the initial direction.
|
||||||
pub fn new(graph: &Graph, start_node: NodeId, initial_direction: Direction) -> Self {
|
pub fn new(graph: &Graph, start_node: NodeId, initial_direction: Direction) -> Self {
|
||||||
let mut traverser = Traverser {
|
let mut traverser = Traverser {
|
||||||
position: Position::AtNode(start_node),
|
position: Position::AtNode(start_node),
|
||||||
@@ -183,12 +281,27 @@ impl Traverser {
|
|||||||
traverser
|
traverser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the next direction for the traverser to take.
|
||||||
|
///
|
||||||
|
/// The direction is buffered and will be applied at the next opportunity,
|
||||||
|
/// typically when the traverser reaches a new node. This allows for responsive
|
||||||
|
/// controls, as the new direction is stored for a limited time.
|
||||||
pub fn set_next_direction(&mut self, new_direction: Direction) {
|
pub fn set_next_direction(&mut self, new_direction: Direction) {
|
||||||
if self.direction != new_direction {
|
if self.direction != new_direction {
|
||||||
self.next_direction = Some((new_direction, 30));
|
self.next_direction = Some((new_direction, 30));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Advances the traverser along the graph by a specified distance.
|
||||||
|
///
|
||||||
|
/// This method updates the traverser's position based on its current state
|
||||||
|
/// and the distance to travel.
|
||||||
|
///
|
||||||
|
/// - If at a node, it checks for a buffered direction to start moving.
|
||||||
|
/// - If between nodes, it moves along the current edge.
|
||||||
|
/// - If it reaches a node, it attempts to transition to a new edge based on
|
||||||
|
/// the buffered direction or by continuing straight.
|
||||||
|
/// - If no valid move is possible, it stops at the node.
|
||||||
pub fn advance(&mut self, graph: &Graph, distance: f32) {
|
pub fn advance(&mut self, graph: &Graph, distance: f32) {
|
||||||
// Decrement the remaining frames for the next direction
|
// Decrement the remaining frames for the next direction
|
||||||
if let Some((direction, remaining)) = self.next_direction {
|
if let Some((direction, remaining)) = self.next_direction {
|
||||||
|
|||||||
52
src/map.rs
52
src/map.rs
@@ -7,17 +7,17 @@ use glam::{IVec2, UVec2, Vec2};
|
|||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
use sdl2::render::{Canvas, RenderTarget};
|
use sdl2::render::{Canvas, RenderTarget};
|
||||||
use smallvec::SmallVec;
|
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::entity::graph::{Graph, Node};
|
use crate::entity::graph::{Graph, Node};
|
||||||
use crate::texture::text::TextTexture;
|
use crate::texture::text::TextTexture;
|
||||||
|
|
||||||
/// The game map.
|
/// The game map, responsible for holding the tile-based layout and the navigation graph.
|
||||||
///
|
///
|
||||||
/// The map is represented as a 2D array of `MapTile`s. It also stores a copy of
|
/// The map is represented as a 2D array of `MapTile`s. It also stores a navigation
|
||||||
/// the original map, which can be used to reset the map to its initial state.
|
/// `Graph` that entities like Pac-Man and ghosts use for movement. The graph is
|
||||||
|
/// generated from the walkable tiles of the map.
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
/// The current state of the map.
|
/// The current state of the map.
|
||||||
current: [[MapTile; BOARD_CELL_SIZE.y as usize]; BOARD_CELL_SIZE.x as usize],
|
current: [[MapTile; BOARD_CELL_SIZE.y as usize]; BOARD_CELL_SIZE.x as usize],
|
||||||
@@ -28,12 +28,16 @@ pub struct Map {
|
|||||||
impl Map {
|
impl Map {
|
||||||
/// Creates a new `Map` instance from a raw board layout.
|
/// Creates a new `Map` instance from a raw board layout.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// This constructor initializes the map tiles based on the provided character layout
|
||||||
|
/// and then generates a navigation graph from the walkable areas.
|
||||||
///
|
///
|
||||||
/// * `raw_board` - A 2D array of characters representing the board layout.
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This function will panic if the board layout contains unknown characters or if
|
||||||
|
/// the house door is not defined by exactly two '=' characters.
|
||||||
pub fn new(raw_board: [&str; BOARD_CELL_SIZE.y as usize]) -> Map {
|
pub fn new(raw_board: [&str; BOARD_CELL_SIZE.y as usize]) -> Map {
|
||||||
let mut map = [[MapTile::Empty; BOARD_CELL_SIZE.y as usize]; BOARD_CELL_SIZE.x as usize];
|
let mut map = [[MapTile::Empty; BOARD_CELL_SIZE.y as usize]; BOARD_CELL_SIZE.x as usize];
|
||||||
let mut house_door = SmallVec::<[IVec2; 2]>::new();
|
let mut house_door = [None; 2];
|
||||||
for (y, line) in raw_board.iter().enumerate().take(BOARD_CELL_SIZE.y as usize) {
|
for (y, line) in raw_board.iter().enumerate().take(BOARD_CELL_SIZE.y as usize) {
|
||||||
for (x, character) in line.chars().enumerate().take(BOARD_CELL_SIZE.x as usize) {
|
for (x, character) in line.chars().enumerate().take(BOARD_CELL_SIZE.x as usize) {
|
||||||
let tile = match character {
|
let tile = match character {
|
||||||
@@ -44,7 +48,11 @@ impl Map {
|
|||||||
'T' => MapTile::Tunnel,
|
'T' => MapTile::Tunnel,
|
||||||
c @ '0'..='4' => MapTile::StartingPosition(c.to_digit(10).unwrap() as u8),
|
c @ '0'..='4' => MapTile::StartingPosition(c.to_digit(10).unwrap() as u8),
|
||||||
'=' => {
|
'=' => {
|
||||||
house_door.push(IVec2::new(x as i32, y as i32));
|
if house_door[0].is_none() {
|
||||||
|
house_door[0] = Some(IVec2::new(x as i32, y as i32));
|
||||||
|
} else {
|
||||||
|
house_door[1] = Some(IVec2::new(x as i32, y as i32));
|
||||||
|
}
|
||||||
MapTile::Wall
|
MapTile::Wall
|
||||||
}
|
}
|
||||||
_ => panic!("Unknown character in board: {character}"),
|
_ => panic!("Unknown character in board: {character}"),
|
||||||
@@ -53,17 +61,17 @@ impl Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if house_door.len() != 2 {
|
if house_door.iter().filter(|x| x.is_some()).count() != 2 {
|
||||||
panic!("House door must have exactly 2 positions");
|
panic!("House door must have exactly 2 positions");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut graph = Self::create_graph(&map);
|
let mut graph = Self::generate_graph(&map);
|
||||||
|
|
||||||
let house_door_node_id = {
|
let house_door_node_id = {
|
||||||
let offset = Vec2::splat(CELL_SIZE as f32 / 2.0);
|
let offset = Vec2::splat(CELL_SIZE as f32 / 2.0);
|
||||||
|
|
||||||
let position_a = house_door[0].as_vec2() * Vec2::splat(CELL_SIZE as f32) + offset;
|
let position_a = house_door[0].unwrap().as_vec2() * Vec2::splat(CELL_SIZE as f32) + offset;
|
||||||
let position_b = house_door[1].as_vec2() * Vec2::splat(CELL_SIZE as f32) + offset;
|
let position_b = house_door[1].unwrap().as_vec2() * Vec2::splat(CELL_SIZE as f32) + offset;
|
||||||
info!("Position A: {position_a}, Position B: {position_b}");
|
info!("Position A: {position_a}, Position B: {position_b}");
|
||||||
let position = position_a.lerp(position_b, 0.5);
|
let position = position_a.lerp(position_b, 0.5);
|
||||||
|
|
||||||
@@ -74,7 +82,13 @@ impl Map {
|
|||||||
Map { current: map, graph }
|
Map { current: map, graph }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_graph(map: &[[MapTile; BOARD_CELL_SIZE.y as usize]; BOARD_CELL_SIZE.x as usize]) -> Graph {
|
/// Generates a navigation graph from the given map layout.
|
||||||
|
///
|
||||||
|
/// This function performs a breadth-first search (BFS) starting from Pac-Man's
|
||||||
|
/// initial position to identify all walkable tiles and create a connected graph.
|
||||||
|
/// Nodes are placed at the center of each walkable tile, and edges are created
|
||||||
|
/// between adjacent walkable tiles.
|
||||||
|
fn generate_graph(map: &[[MapTile; BOARD_CELL_SIZE.y as usize]; BOARD_CELL_SIZE.x as usize]) -> Graph {
|
||||||
let mut graph = Graph::new();
|
let mut graph = Graph::new();
|
||||||
let mut grid_to_node = HashMap::new();
|
let mut grid_to_node = HashMap::new();
|
||||||
|
|
||||||
@@ -160,7 +174,7 @@ impl Map {
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// The starting position as UVec2, or None if not found
|
/// The starting position as a grid coordinate (`UVec2`), or `None` if not found.
|
||||||
pub fn find_starting_position(&self, entity_id: u8) -> Option<UVec2> {
|
pub fn find_starting_position(&self, entity_id: u8) -> Option<UVec2> {
|
||||||
for (x, col) in self.current.iter().enumerate().take(BOARD_CELL_SIZE.x as usize) {
|
for (x, col) in self.current.iter().enumerate().take(BOARD_CELL_SIZE.x as usize) {
|
||||||
for (y, &cell) in col.iter().enumerate().take(BOARD_CELL_SIZE.y as usize) {
|
for (y, &cell) in col.iter().enumerate().take(BOARD_CELL_SIZE.y as usize) {
|
||||||
@@ -174,7 +188,10 @@ impl Map {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the map to the given canvas using the provided map texture.
|
/// Renders the map to the given canvas.
|
||||||
|
///
|
||||||
|
/// This function draws the static map texture to the screen at the correct
|
||||||
|
/// position and scale.
|
||||||
pub fn render<T: RenderTarget>(&self, canvas: &mut Canvas<T>, atlas: &mut SpriteAtlas, map_texture: &mut AtlasTile) {
|
pub fn render<T: RenderTarget>(&self, canvas: &mut Canvas<T>, atlas: &mut SpriteAtlas, map_texture: &mut AtlasTile) {
|
||||||
let dest = Rect::new(
|
let dest = Rect::new(
|
||||||
BOARD_PIXEL_OFFSET.x as i32,
|
BOARD_PIXEL_OFFSET.x as i32,
|
||||||
@@ -185,6 +202,11 @@ impl Map {
|
|||||||
let _ = map_texture.render(canvas, atlas, dest);
|
let _ = map_texture.render(canvas, atlas, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Renders a debug visualization of the navigation graph.
|
||||||
|
///
|
||||||
|
/// This function is intended for development and debugging purposes. It draws the
|
||||||
|
/// nodes and edges of the graph on top of the map, allowing for visual
|
||||||
|
/// inspection of the navigation paths.
|
||||||
pub fn debug_render_nodes<T: RenderTarget>(&self, canvas: &mut Canvas<T>, atlas: &mut SpriteAtlas, text: &mut TextTexture) {
|
pub fn debug_render_nodes<T: RenderTarget>(&self, canvas: &mut Canvas<T>, atlas: &mut SpriteAtlas, text: &mut TextTexture) {
|
||||||
for i in 0..self.graph.node_count() {
|
for i in 0..self.graph.node_count() {
|
||||||
let node = self.graph.get_node(i).unwrap();
|
let node = self.graph.get_node(i).unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user