From 328098bbe7019104d9994fa597c77ef1163e7e4f Mon Sep 17 00:00:00 2001 From: Urban Modig Date: Tue, 2 Sep 2025 21:47:50 +0200 Subject: [PATCH] Refactor PacMan to utilize SpriteSheetManager. Replaced hardcoded sprite loading logic with centralized SpriteSheetManager to improve maintainability and reduce duplication. Adjusted related methods to use the new Sprites record for streamlined sprite management. --- .../se/urmo/game/entities/pacman/PacMan.java | 74 +++++++++---------- .../se/urmo/game/graphics/SpriteLocation.java | 2 + 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/main/java/se/urmo/game/entities/pacman/PacMan.java b/src/main/java/se/urmo/game/entities/pacman/PacMan.java index ef57d4c..eef21ca 100644 --- a/src/main/java/se/urmo/game/entities/pacman/PacMan.java +++ b/src/main/java/se/urmo/game/entities/pacman/PacMan.java @@ -5,13 +5,18 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import se.urmo.game.collision.CollisionChecker; import se.urmo.game.entities.BaseAnimated; +import se.urmo.game.graphics.SpriteLocation; +import se.urmo.game.graphics.SpriteSheetManager; +import se.urmo.game.map.GameMap; import se.urmo.game.state.LevelManager; import se.urmo.game.util.Direction; -import se.urmo.game.map.GameMap; import se.urmo.game.util.LoadSave; import se.urmo.game.util.MyPoint; -import java.awt.*; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.util.Arrays; import java.util.stream.Stream; @@ -19,32 +24,25 @@ import java.util.stream.Stream; @Slf4j public class PacMan extends BaseAnimated { - private enum PacmanState { - ALIVE, DYING, DEAD - } - public static final int PACMAN_SIZE = 32; public static final int PACMAN_OFFSET = PACMAN_SIZE / 2; private static final int COLLISION_BOX_SIZE = 16; private static final int COLLISION_BOX_OFFSET = (PACMAN_SIZE - COLLISION_BOX_SIZE) / 2; - private final MyPoint startPosition; private static final int ANIMATION_UPDATE_FREQUENCY = 10; private static final double BASE_SPEED = 0.40; - private boolean moving = false; - private final BufferedImage[][] spriteSheets;// [row][col] - private MyPoint position; + private static final long FRAME_NS = 80_000_000L; // 80 ms + private final MyPoint startPosition; private final CollisionChecker collisionChecker; private final LevelManager levelManager; + private final Sprites sprites; + private boolean moving = false; + private MyPoint position; @Setter @Getter private Direction direction = Direction.NONE; - private double pacmanLevelSpeed; - - private static BufferedImage[] deathFramesBase; // original, flattened [0..7] + private final double pacmanLevelSpeed; private BufferedImage[] deathFrames; // working copy private long lastChangeNs; - private static final long FRAME_NS = 80_000_000L; // 80 ms - // animation state @Setter private PacmanState state = PacmanState.ALIVE; @@ -58,40 +56,31 @@ public class PacMan extends BaseAnimated { 26 * GameMap.MAP_TILESIZE + GameMap.OFFSET_X, 13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + ((double) GameMap.MAP_TILESIZE / 2)); this.startPosition = this.position; - Sprites spriteSheets1 = loadAnimation(); - this.spriteSheets = spriteSheets1.spriteSheets; - this.deathFramesBase = spriteSheets1.deathFrames; - this.pacmanLevelSpeed = this.levelManager.getPacmanLevelSpeed(); - } + this.sprites = loadAnimation(); + + this.pacmanLevelSpeed = this.levelManager.getPacmanLevelSpeed(); - record Sprites(BufferedImage[][] spriteSheets, BufferedImage[] deathFrames) { } private Sprites loadAnimation() { - BufferedImage[][] image = new BufferedImage[3][4]; BufferedImage[][] spriteMap = new BufferedImage[6][4]; BufferedImage[] deathFrames; - BufferedImage img = LoadSave.GetSpriteAtlas("sprites/PacManAssets-PacMan.png"); - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 4; col++) { - image[row][col] = img.getSubimage(PACMAN_SIZE * col, PACMAN_SIZE * row, PACMAN_SIZE, PACMAN_SIZE); - } - } - spriteMap[Direction.RIGHT.ordinal()] = image[0]; - spriteMap[Direction.LEFT.ordinal()] = Arrays.stream(image[0]) + BufferedImage[] animation = SpriteSheetManager.get(SpriteLocation.PACMAN).getAnimation(0); + spriteMap[Direction.RIGHT.ordinal()] = animation; + spriteMap[Direction.LEFT.ordinal()] = Arrays.stream(animation) .map(i -> LoadSave.rotate(i, Direction.LEFT.angel)) .toArray(BufferedImage[]::new); - spriteMap[Direction.DOWN.ordinal()] = Arrays.stream(image[0]) + spriteMap[Direction.DOWN.ordinal()] = Arrays.stream(animation) .map(i -> LoadSave.rotate(i, 90)) .toArray(BufferedImage[]::new); - spriteMap[Direction.UP.ordinal()] = Arrays.stream(image[0]) + spriteMap[Direction.UP.ordinal()] = Arrays.stream(animation) .map(i -> LoadSave.rotate(i, 270)) .toArray(BufferedImage[]::new); - deathFrames = Stream.concat(Arrays.stream(image[1]), Arrays.stream(image[2])) + deathFrames = Stream.concat( + Arrays.stream(SpriteSheetManager.get(SpriteLocation.PACMAN).getAnimation(1)), + Arrays.stream(SpriteSheetManager.get(SpriteLocation.PACMAN).getAnimation(2))) .toArray(BufferedImage[]::new); - - return new Sprites(spriteMap, deathFrames); } @@ -105,7 +94,7 @@ public class PacMan extends BaseAnimated { private void drawAlive(Graphics g) { if (state != PacmanState.ALIVE) return; // ignore if not dying/dead g.drawImage( - spriteSheets[direction == Direction.NONE ? 0 : direction.ordinal()][aniIndex], + sprites.spriteSheets[direction == Direction.NONE ? 0 : direction.ordinal()][aniIndex], (int) position.x - PACMAN_OFFSET, (int) position.y - PACMAN_OFFSET, PACMAN_SIZE, @@ -136,7 +125,7 @@ public class PacMan extends BaseAnimated { if (state != PacmanState.DYING) return; long now = System.nanoTime(); - while (now - lastChangeNs >= FRAME_NS && deathFrameIdx < deathFramesBase.length - 1) { + while (now - lastChangeNs >= FRAME_NS && deathFrameIdx < sprites.deathFrames.length - 1) { deathFrameIdx++; lastChangeNs += FRAME_NS; // carry over exact cadence } @@ -168,7 +157,7 @@ public class PacMan extends BaseAnimated { state = PacmanState.DYING; deathFrameIdx = 0; lastChangeNs = System.nanoTime(); // reset stopwatch right now - deathFrames = Arrays.stream(deathFramesBase) + deathFrames = Arrays.stream(sprites.deathFrames) .map(img -> LoadSave.rotate(img, direction.angel)) .toArray(BufferedImage[]::new); } @@ -197,7 +186,7 @@ public class PacMan extends BaseAnimated { } public Image getLifeIcon() { - return spriteSheets[0][1]; + return sprites.spriteSheets[0][1]; } public Rectangle getBounds() { @@ -225,4 +214,11 @@ public class PacMan extends BaseAnimated { // PACMAN_SIZE, // PACMAN_SIZE, null); } + + private enum PacmanState { + ALIVE, DYING, DEAD + } + + record Sprites(BufferedImage[][] spriteSheets, BufferedImage[] deathFrames) { + } } diff --git a/src/main/java/se/urmo/game/graphics/SpriteLocation.java b/src/main/java/se/urmo/game/graphics/SpriteLocation.java index 1323363..0ad637f 100644 --- a/src/main/java/se/urmo/game/graphics/SpriteLocation.java +++ b/src/main/java/se/urmo/game/graphics/SpriteLocation.java @@ -2,6 +2,7 @@ package se.urmo.game.graphics; import lombok.Getter; import se.urmo.game.entities.ghost.Ghost; +import se.urmo.game.entities.pacman.PacMan; import se.urmo.game.map.GameMap; import se.urmo.game.util.LoadSave; @@ -12,6 +13,7 @@ public enum SpriteLocation { MAP("sprites/PacMan-custom-spritemap-0-3.png", 5, 11, GameMap.MAP_TILESIZE), ITEM("sprites/PacManAssets-Items.png", 2, 8, GameMap.MAP_TILESIZE), GHOST("sprites/PacManAssets-Ghosts.png", 11, 4, Ghost.GHOST_SIZE), + PACMAN("sprites/PacManAssets-PacMan.png", 3, 4, PacMan.PACMAN_SIZE), NONE("", 0, 0, 0) { // Special case for tiles without sprites @Override public BufferedImage[][] loadSprites(int tileSize) {