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) {