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.
This commit is contained in:
@ -5,13 +5,18 @@ import lombok.Setter;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import se.urmo.game.collision.CollisionChecker;
|
import se.urmo.game.collision.CollisionChecker;
|
||||||
import se.urmo.game.entities.BaseAnimated;
|
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.state.LevelManager;
|
||||||
import se.urmo.game.util.Direction;
|
import se.urmo.game.util.Direction;
|
||||||
import se.urmo.game.map.GameMap;
|
|
||||||
import se.urmo.game.util.LoadSave;
|
import se.urmo.game.util.LoadSave;
|
||||||
import se.urmo.game.util.MyPoint;
|
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.awt.image.BufferedImage;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -19,32 +24,25 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PacMan extends BaseAnimated {
|
public class PacMan extends BaseAnimated {
|
||||||
private enum PacmanState {
|
|
||||||
ALIVE, DYING, DEAD
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int PACMAN_SIZE = 32;
|
public static final int PACMAN_SIZE = 32;
|
||||||
public static final int PACMAN_OFFSET = PACMAN_SIZE / 2;
|
public static final int PACMAN_OFFSET = PACMAN_SIZE / 2;
|
||||||
private static final int COLLISION_BOX_SIZE = 16;
|
private static final int COLLISION_BOX_SIZE = 16;
|
||||||
private static final int COLLISION_BOX_OFFSET = (PACMAN_SIZE - COLLISION_BOX_SIZE) / 2;
|
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 int ANIMATION_UPDATE_FREQUENCY = 10;
|
||||||
private static final double BASE_SPEED = 0.40;
|
private static final double BASE_SPEED = 0.40;
|
||||||
private boolean moving = false;
|
private static final long FRAME_NS = 80_000_000L; // 80 ms
|
||||||
private final BufferedImage[][] spriteSheets;// [row][col]
|
private final MyPoint startPosition;
|
||||||
private MyPoint position;
|
|
||||||
private final CollisionChecker collisionChecker;
|
private final CollisionChecker collisionChecker;
|
||||||
private final LevelManager levelManager;
|
private final LevelManager levelManager;
|
||||||
|
private final Sprites sprites;
|
||||||
|
private boolean moving = false;
|
||||||
|
private MyPoint position;
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
private Direction direction = Direction.NONE;
|
private Direction direction = Direction.NONE;
|
||||||
private double pacmanLevelSpeed;
|
private final double pacmanLevelSpeed;
|
||||||
|
|
||||||
private static BufferedImage[] deathFramesBase; // original, flattened [0..7]
|
|
||||||
private BufferedImage[] deathFrames; // working copy
|
private BufferedImage[] deathFrames; // working copy
|
||||||
private long lastChangeNs;
|
private long lastChangeNs;
|
||||||
private static final long FRAME_NS = 80_000_000L; // 80 ms
|
|
||||||
|
|
||||||
// animation state
|
// animation state
|
||||||
@Setter
|
@Setter
|
||||||
private PacmanState state = PacmanState.ALIVE;
|
private PacmanState state = PacmanState.ALIVE;
|
||||||
@ -58,40 +56,31 @@ public class PacMan extends BaseAnimated {
|
|||||||
26 * GameMap.MAP_TILESIZE + GameMap.OFFSET_X,
|
26 * GameMap.MAP_TILESIZE + GameMap.OFFSET_X,
|
||||||
13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + ((double) GameMap.MAP_TILESIZE / 2));
|
13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + ((double) GameMap.MAP_TILESIZE / 2));
|
||||||
this.startPosition = this.position;
|
this.startPosition = this.position;
|
||||||
Sprites spriteSheets1 = loadAnimation();
|
this.sprites = loadAnimation();
|
||||||
this.spriteSheets = spriteSheets1.spriteSheets;
|
|
||||||
this.deathFramesBase = spriteSheets1.deathFrames;
|
this.pacmanLevelSpeed = this.levelManager.getPacmanLevelSpeed();
|
||||||
this.pacmanLevelSpeed = this.levelManager.getPacmanLevelSpeed();
|
|
||||||
}
|
|
||||||
|
|
||||||
record Sprites(BufferedImage[][] spriteSheets, BufferedImage[] deathFrames) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Sprites loadAnimation() {
|
private Sprites loadAnimation() {
|
||||||
BufferedImage[][] image = new BufferedImage[3][4];
|
|
||||||
BufferedImage[][] spriteMap = new BufferedImage[6][4];
|
BufferedImage[][] spriteMap = new BufferedImage[6][4];
|
||||||
BufferedImage[] deathFrames;
|
BufferedImage[] deathFrames;
|
||||||
|
|
||||||
BufferedImage img = LoadSave.GetSpriteAtlas("sprites/PacManAssets-PacMan.png");
|
BufferedImage[] animation = SpriteSheetManager.get(SpriteLocation.PACMAN).getAnimation(0);
|
||||||
for (int row = 0; row < 3; row++) {
|
spriteMap[Direction.RIGHT.ordinal()] = animation;
|
||||||
for (int col = 0; col < 4; col++) {
|
spriteMap[Direction.LEFT.ordinal()] = Arrays.stream(animation)
|
||||||
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])
|
|
||||||
.map(i -> LoadSave.rotate(i, Direction.LEFT.angel))
|
.map(i -> LoadSave.rotate(i, Direction.LEFT.angel))
|
||||||
.toArray(BufferedImage[]::new);
|
.toArray(BufferedImage[]::new);
|
||||||
spriteMap[Direction.DOWN.ordinal()] = Arrays.stream(image[0])
|
spriteMap[Direction.DOWN.ordinal()] = Arrays.stream(animation)
|
||||||
.map(i -> LoadSave.rotate(i, 90))
|
.map(i -> LoadSave.rotate(i, 90))
|
||||||
.toArray(BufferedImage[]::new);
|
.toArray(BufferedImage[]::new);
|
||||||
spriteMap[Direction.UP.ordinal()] = Arrays.stream(image[0])
|
spriteMap[Direction.UP.ordinal()] = Arrays.stream(animation)
|
||||||
.map(i -> LoadSave.rotate(i, 270))
|
.map(i -> LoadSave.rotate(i, 270))
|
||||||
.toArray(BufferedImage[]::new);
|
.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);
|
.toArray(BufferedImage[]::new);
|
||||||
|
|
||||||
|
|
||||||
return new Sprites(spriteMap, deathFrames);
|
return new Sprites(spriteMap, deathFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +94,7 @@ public class PacMan extends BaseAnimated {
|
|||||||
private void drawAlive(Graphics g) {
|
private void drawAlive(Graphics g) {
|
||||||
if (state != PacmanState.ALIVE) return; // ignore if not dying/dead
|
if (state != PacmanState.ALIVE) return; // ignore if not dying/dead
|
||||||
g.drawImage(
|
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.x - PACMAN_OFFSET,
|
||||||
(int) position.y - PACMAN_OFFSET,
|
(int) position.y - PACMAN_OFFSET,
|
||||||
PACMAN_SIZE,
|
PACMAN_SIZE,
|
||||||
@ -136,7 +125,7 @@ public class PacMan extends BaseAnimated {
|
|||||||
if (state != PacmanState.DYING) return;
|
if (state != PacmanState.DYING) return;
|
||||||
|
|
||||||
long now = System.nanoTime();
|
long now = System.nanoTime();
|
||||||
while (now - lastChangeNs >= FRAME_NS && deathFrameIdx < deathFramesBase.length - 1) {
|
while (now - lastChangeNs >= FRAME_NS && deathFrameIdx < sprites.deathFrames.length - 1) {
|
||||||
deathFrameIdx++;
|
deathFrameIdx++;
|
||||||
lastChangeNs += FRAME_NS; // carry over exact cadence
|
lastChangeNs += FRAME_NS; // carry over exact cadence
|
||||||
}
|
}
|
||||||
@ -168,7 +157,7 @@ public class PacMan extends BaseAnimated {
|
|||||||
state = PacmanState.DYING;
|
state = PacmanState.DYING;
|
||||||
deathFrameIdx = 0;
|
deathFrameIdx = 0;
|
||||||
lastChangeNs = System.nanoTime(); // reset stopwatch right now
|
lastChangeNs = System.nanoTime(); // reset stopwatch right now
|
||||||
deathFrames = Arrays.stream(deathFramesBase)
|
deathFrames = Arrays.stream(sprites.deathFrames)
|
||||||
.map(img -> LoadSave.rotate(img, direction.angel))
|
.map(img -> LoadSave.rotate(img, direction.angel))
|
||||||
.toArray(BufferedImage[]::new);
|
.toArray(BufferedImage[]::new);
|
||||||
}
|
}
|
||||||
@ -197,7 +186,7 @@ public class PacMan extends BaseAnimated {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Image getLifeIcon() {
|
public Image getLifeIcon() {
|
||||||
return spriteSheets[0][1];
|
return sprites.spriteSheets[0][1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rectangle getBounds() {
|
public Rectangle getBounds() {
|
||||||
@ -225,4 +214,11 @@ public class PacMan extends BaseAnimated {
|
|||||||
// PACMAN_SIZE,
|
// PACMAN_SIZE,
|
||||||
// PACMAN_SIZE, null);
|
// PACMAN_SIZE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum PacmanState {
|
||||||
|
ALIVE, DYING, DEAD
|
||||||
|
}
|
||||||
|
|
||||||
|
record Sprites(BufferedImage[][] spriteSheets, BufferedImage[] deathFrames) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package se.urmo.game.graphics;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import se.urmo.game.entities.ghost.Ghost;
|
import se.urmo.game.entities.ghost.Ghost;
|
||||||
|
import se.urmo.game.entities.pacman.PacMan;
|
||||||
import se.urmo.game.map.GameMap;
|
import se.urmo.game.map.GameMap;
|
||||||
import se.urmo.game.util.LoadSave;
|
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),
|
MAP("sprites/PacMan-custom-spritemap-0-3.png", 5, 11, GameMap.MAP_TILESIZE),
|
||||||
ITEM("sprites/PacManAssets-Items.png", 2, 8, GameMap.MAP_TILESIZE),
|
ITEM("sprites/PacManAssets-Items.png", 2, 8, GameMap.MAP_TILESIZE),
|
||||||
GHOST("sprites/PacManAssets-Ghosts.png", 11, 4, Ghost.GHOST_SIZE),
|
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
|
NONE("", 0, 0, 0) { // Special case for tiles without sprites
|
||||||
@Override
|
@Override
|
||||||
public BufferedImage[][] loadSprites(int tileSize) {
|
public BufferedImage[][] loadSprites(int tileSize) {
|
||||||
|
|||||||
Reference in New Issue
Block a user