feat: setup dying sprites with sprite validation tests

This commit is contained in:
Ryan Walters
2025-09-06 10:38:49 -05:00
parent 9633611ae8
commit b85b7a4f9b
2 changed files with 118 additions and 38 deletions

View File

@@ -15,6 +15,8 @@ pub enum PacmanSprite {
Moving(Direction, u8), Moving(Direction, u8),
/// The full, closed-mouth Pac-Man sprite. /// The full, closed-mouth Pac-Man sprite.
Full, Full,
/// A single frame of the dying animation.
Dying(u8),
} }
/// Represents the color of a frightened ghost. /// Represents the color of a frightened ghost.
@@ -60,45 +62,50 @@ impl GameSprite {
/// This path corresponds to the filename in the texture atlas JSON file. /// This path corresponds to the filename in the texture atlas JSON file.
pub fn to_path(self) -> String { pub fn to_path(self) -> String {
match self { match self {
GameSprite::Pacman(sprite) => match sprite { GameSprite::Pacman(PacmanSprite::Moving(dir, frame)) => format!(
PacmanSprite::Moving(dir, frame) => { "pacman/{}_{}.png",
let frame_char = match frame { dir.as_ref(),
0 => 'a', match frame {
1 => 'b', 0 => "a",
_ => panic!("Invalid animation frame"), 1 => "b",
}; _ => panic!("Invalid animation frame"),
format!("pacman/{}_{}.png", dir.as_ref().to_lowercase(), frame_char)
} }
PacmanSprite::Full => "pacman/full.png".to_string(), ),
}, GameSprite::Pacman(PacmanSprite::Full) => "pacman/full.png".to_string(),
GameSprite::Ghost(sprite) => match sprite { GameSprite::Pacman(PacmanSprite::Dying(frame)) => format!("pacman/death/{}.png", frame),
GhostSprite::Normal(ghost, dir, frame) => {
let frame_char = match frame { // Ghost sprites
0 => 'a', GameSprite::Ghost(GhostSprite::Normal(ghost_type, dir, frame)) => {
1 => 'b', let frame_char = match frame {
_ => panic!("Invalid animation frame"), 0 => 'a',
}; 1 => 'b',
format!("ghost/{}/{}_{}.png", ghost.as_str(), dir.as_ref().to_lowercase(), frame_char) _ => panic!("Invalid animation frame"),
} };
GhostSprite::Frightened(color, frame) => { format!(
let frame_char = match frame { "ghost/{}/{}_{}.png",
0 => 'a', ghost_type.as_str(),
1 => 'b', dir.as_ref().to_lowercase(),
_ => panic!("Invalid animation frame"), frame_char
}; )
let color_str = match color { }
FrightenedColor::Blue => "blue", GameSprite::Ghost(GhostSprite::Frightened(color, frame)) => {
FrightenedColor::White => "white", let frame_char = match frame {
}; 0 => 'a',
format!("ghost/frightened/{}_{}.png", color_str, frame_char) 1 => 'b',
} _ => panic!("Invalid animation frame"),
GhostSprite::Eyes(dir) => format!("ghost/eyes/{}.png", dir.as_ref().to_lowercase()), };
}, let color_str = match color {
GameSprite::Maze(sprite) => match sprite { FrightenedColor::Blue => "blue",
MazeSprite::Tile(index) => format!("maze/tiles/{}.png", index), FrightenedColor::White => "white",
MazeSprite::Pellet => "maze/pellet.png".to_string(), };
MazeSprite::Energizer => "maze/energizer.png".to_string(), format!("ghost/frightened/{}_{}.png", color_str, frame_char)
}, }
GameSprite::Ghost(GhostSprite::Eyes(dir)) => format!("ghost/eyes/{}.png", dir.as_ref().to_lowercase()),
// Maze sprites
GameSprite::Maze(MazeSprite::Tile(index)) => format!("maze/tiles/{}.png", index),
GameSprite::Maze(MazeSprite::Pellet) => "maze/pellet.png".to_string(),
GameSprite::Maze(MazeSprite::Energizer) => "maze/energizer.png".to_string(),
} }
} }
} }

73
tests/sprites.rs Normal file
View File

@@ -0,0 +1,73 @@
//! Tests for the sprite path generation.
use pacman::{
game::ATLAS_FRAMES,
map::direction::Direction,
systems::components::Ghost,
texture::sprites::{FrightenedColor, GameSprite, GhostSprite, MazeSprite, PacmanSprite},
};
#[test]
fn test_all_sprite_paths_exist() {
let mut sprites_to_test = Vec::new();
// Pac-Man sprites
for &dir in &[Direction::Up, Direction::Down, Direction::Left, Direction::Right] {
for frame in 0..2 {
sprites_to_test.push(GameSprite::Pacman(PacmanSprite::Moving(dir, frame)));
}
}
sprites_to_test.push(GameSprite::Pacman(PacmanSprite::Full));
for frame in 0..=10 {
sprites_to_test.push(GameSprite::Pacman(PacmanSprite::Dying(frame)));
}
// Ghost sprites
for &ghost in &[Ghost::Blinky, Ghost::Pinky, Ghost::Inky, Ghost::Clyde] {
for &dir in &[Direction::Up, Direction::Down, Direction::Left, Direction::Right] {
for frame in 0..2 {
sprites_to_test.push(GameSprite::Ghost(GhostSprite::Normal(ghost, dir, frame)));
}
sprites_to_test.push(GameSprite::Ghost(GhostSprite::Eyes(dir)));
}
}
for &color in &[FrightenedColor::Blue, FrightenedColor::White] {
for frame in 0..2 {
sprites_to_test.push(GameSprite::Ghost(GhostSprite::Frightened(color, frame)));
}
}
// Maze sprites
for i in 0..=34 {
sprites_to_test.push(GameSprite::Maze(MazeSprite::Tile(i)));
}
sprites_to_test.push(GameSprite::Maze(MazeSprite::Pellet));
sprites_to_test.push(GameSprite::Maze(MazeSprite::Energizer));
for sprite in sprites_to_test {
let path = sprite.to_path();
assert!(
ATLAS_FRAMES.contains_key(&path),
"Sprite path '{}' does not exist in the atlas.",
path
);
}
}
#[test]
fn test_invalid_sprite_paths_do_not_exist() {
let invalid_sprites = vec![
// An invalid Pac-Man dying frame
GameSprite::Pacman(PacmanSprite::Dying(99)),
// An invalid maze tile
GameSprite::Maze(MazeSprite::Tile(99)),
];
for sprite in invalid_sprites {
let path = sprite.to_path();
assert!(
!ATLAS_FRAMES.contains_key(&path),
"Invalid sprite path '{}' was found in the atlas, but it should not exist.",
path
);
}
}