diff --git a/src/texture/sprites.rs b/src/texture/sprites.rs index 2d84e16..6eca64c 100644 --- a/src/texture/sprites.rs +++ b/src/texture/sprites.rs @@ -15,6 +15,8 @@ pub enum PacmanSprite { Moving(Direction, u8), /// The full, closed-mouth Pac-Man sprite. Full, + /// A single frame of the dying animation. + Dying(u8), } /// 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. pub fn to_path(self) -> String { match self { - GameSprite::Pacman(sprite) => match sprite { - PacmanSprite::Moving(dir, frame) => { - let frame_char = match frame { - 0 => 'a', - 1 => 'b', - _ => panic!("Invalid animation frame"), - }; - format!("pacman/{}_{}.png", dir.as_ref().to_lowercase(), frame_char) + GameSprite::Pacman(PacmanSprite::Moving(dir, frame)) => format!( + "pacman/{}_{}.png", + dir.as_ref(), + match frame { + 0 => "a", + 1 => "b", + _ => panic!("Invalid animation frame"), } - PacmanSprite::Full => "pacman/full.png".to_string(), - }, - GameSprite::Ghost(sprite) => match sprite { - GhostSprite::Normal(ghost, dir, frame) => { - let frame_char = match frame { - 0 => 'a', - 1 => 'b', - _ => panic!("Invalid animation frame"), - }; - format!("ghost/{}/{}_{}.png", ghost.as_str(), dir.as_ref().to_lowercase(), frame_char) - } - GhostSprite::Frightened(color, frame) => { - let frame_char = match frame { - 0 => 'a', - 1 => 'b', - _ => panic!("Invalid animation frame"), - }; - let color_str = match color { - FrightenedColor::Blue => "blue", - FrightenedColor::White => "white", - }; - format!("ghost/frightened/{}_{}.png", color_str, frame_char) - } - GhostSprite::Eyes(dir) => format!("ghost/eyes/{}.png", dir.as_ref().to_lowercase()), - }, - GameSprite::Maze(sprite) => match sprite { - MazeSprite::Tile(index) => format!("maze/tiles/{}.png", index), - MazeSprite::Pellet => "maze/pellet.png".to_string(), - MazeSprite::Energizer => "maze/energizer.png".to_string(), - }, + ), + GameSprite::Pacman(PacmanSprite::Full) => "pacman/full.png".to_string(), + GameSprite::Pacman(PacmanSprite::Dying(frame)) => format!("pacman/death/{}.png", frame), + + // Ghost sprites + GameSprite::Ghost(GhostSprite::Normal(ghost_type, dir, frame)) => { + let frame_char = match frame { + 0 => 'a', + 1 => 'b', + _ => panic!("Invalid animation frame"), + }; + format!( + "ghost/{}/{}_{}.png", + ghost_type.as_str(), + dir.as_ref().to_lowercase(), + frame_char + ) + } + GameSprite::Ghost(GhostSprite::Frightened(color, frame)) => { + let frame_char = match frame { + 0 => 'a', + 1 => 'b', + _ => panic!("Invalid animation frame"), + }; + let color_str = match color { + FrightenedColor::Blue => "blue", + FrightenedColor::White => "white", + }; + 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(), } } } diff --git a/tests/sprites.rs b/tests/sprites.rs new file mode 100644 index 0000000..c7cfce4 --- /dev/null +++ b/tests/sprites.rs @@ -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 + ); + } +}