Added mode-management and second ghost

This commit is contained in:
Urban Modig
2025-08-17 22:10:10 +02:00
parent a2b9b2264e
commit 9d06b038e0
8 changed files with 125 additions and 40 deletions

View File

@ -4,7 +4,7 @@ import java.awt.Point;
public class BlinkyStrategy implements GhostStrategy {
@Override
public Point chooseTarget(PacMan pacman, Ghost self, Ghost blinky) {
public Point chooseTarget(PacMan pacman) {
return pacman.getTilePosition();
}
}

View File

@ -2,10 +2,9 @@ package se.urmo.game.entities;
import lombok.extern.slf4j.Slf4j;
import se.urmo.game.collision.GhostCollisionChecker;
import se.urmo.game.main.Game;
import se.urmo.game.map.GameMap;
import se.urmo.game.state.GhostManager;
import se.urmo.game.util.Direction;
import se.urmo.game.util.LoadSave;
import se.urmo.game.util.MiscUtil;
import java.awt.Color;
@ -13,53 +12,40 @@ import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class Ghost {
private static final int COLLISION_BOX_SIZE = 16;
private static final int GHOST_SPEED = 1;
private static final int GHOST_MOVEMENT_UPDATE_FREQUENCY = 2;
private static int GHOST_SIZE = 32;
public static final int GHOST_SIZE = 32;
private static final int ANIMATION_UPDATE_FREQUENCY = 25;
private static final int COLLISION_BOX_OFFSET = COLLISION_BOX_SIZE / 2;
private static final BufferedImage COLLISION_BOX = MiscUtil.createOutlinedBox(COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, Color.black, 2);
private final Game game;
private final GhostCollisionChecker collisionChecker;
private final GhostStrategy strategy;
private final GhostStrategy chaseStrategy;
private Point position;
private boolean moving = true;
private int aniTick = 0;
private int aniIndex = 0;
private BufferedImage[] animation;
private final BufferedImage[] animation;
private int movementTick = 0;
private Direction direction;
private Direction prevDirection;
private GhostMode mode;
private GhostStrategy currentStrategy;
public Ghost(Game game, GhostCollisionChecker collisionChecker, GhostStrategy strategy) {
this.game = game;
public Ghost(GhostCollisionChecker collisionChecker, GhostStrategy strategy, BufferedImage[] animation) {
this.collisionChecker = collisionChecker;
this.strategy = strategy;
this.chaseStrategy = strategy;
this.currentStrategy = strategy;
this.animation = animation;
position = new Point(
13 * GameMap.MAP_TILESIZE + (GameMap.MAP_TILESIZE / 2) + GameMap.OFFSET_X,
4 * GameMap.MAP_TILESIZE + (GameMap.MAP_TILESIZE / 2) + GameMap.OFFSET_Y);
loadAnimation();
}
private void loadAnimation() {
BufferedImage[][] image = new BufferedImage[10][4];
BufferedImage img = LoadSave.GetSpriteAtlas("sprites/PacManAssets-Ghosts.png");
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 4; col++) {
image[row][col] = img.getSubimage(32 * col, 32 * row, GHOST_SIZE, GHOST_SIZE);
}
}
animation = image[0];
}
public void draw(Graphics g) {
@ -88,7 +74,7 @@ public class Ghost {
prevDirection = direction;
direction = chooseDirection(
collisionChecker.calculateDirectionAlternatives(position),
strategy.chooseTarget(pacman, null, null),
currentStrategy.chooseTarget(pacman),
prevDirection);
log.info("selecting direction {}", direction);
}
@ -139,7 +125,7 @@ public class Ghost {
if (aniTick >= ANIMATION_UPDATE_FREQUENCY) {
aniTick = 0;
aniIndex++;
if (aniIndex >= 3) {
if (aniIndex >= GhostManager.MAX_SPRITE_FRAMES) {
aniIndex = 0;
}
@ -147,4 +133,13 @@ public class Ghost {
}
}
public void setMode(GhostMode mode) {
this.mode = mode;
switch (mode) {
case CHASE -> currentStrategy = chaseStrategy;
case SCATTER -> currentStrategy = null;
case FRIGHTENED -> currentStrategy = null;
case EATEN -> currentStrategy = null;
}
}
}

View File

@ -0,0 +1,8 @@
package se.urmo.game.entities;
public enum GhostMode {
CHASE,
SCATTER,
FRIGHTENED,
EATEN
}

View File

@ -3,5 +3,5 @@ package se.urmo.game.entities;
import java.awt.Point;
public interface GhostStrategy {
Point chooseTarget(PacMan pacman, Ghost self, Ghost blinky);
Point chooseTarget(PacMan pacman);
}

View File

@ -1,5 +1,7 @@
package se.urmo.game.entities;
import lombok.Getter;
import lombok.Setter;
import se.urmo.game.collision.CollisionChecker;
import se.urmo.game.util.Direction;
import se.urmo.game.main.Game;
@ -21,11 +23,14 @@ public class PacMan {
private int aniIndex = 0;
private static final int ANIMATION_UPDATE_FREQUENCY = 25;
private int speed = 1;
@Setter
private boolean moving;
private final BufferedImage[][] movmentImages = new BufferedImage[4][4];
private Point position;
private static final BufferedImage COLLISION_BOX = MiscUtil.createOutlinedBox(COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, Color.yellow, 2);
private CollisionChecker collisionChecker;
@Setter
@Getter
private Direction direction = Direction.NONE;
public PacMan(Game game, CollisionChecker collisionChecker) {
@ -102,14 +107,6 @@ public class PacMan {
}
}
public void setMoving(boolean moving) {
this.moving = moving;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public Point getTilePosition() {
return position;
}

View File

@ -0,0 +1,21 @@
package se.urmo.game.entities;
import se.urmo.game.util.Direction;
import java.awt.Point;
public class PinkyStrategy implements GhostStrategy{
@Override
public Point chooseTarget(PacMan pacman) {
Direction pacmanDir = pacman.getDirection();
Point pacmanPos = pacman.getTilePosition();
return switch (pacmanDir){
case RIGHT -> new Point(pacmanPos.x + 4 * 16, pacmanPos.y);
case LEFT -> new Point(pacmanPos.x - 4 * 16, pacmanPos.y);
case DOWN -> new Point(pacmanPos.x, pacmanPos.y + 4 * 16);
case UP -> new Point(pacmanPos.x, pacmanPos.y - 4 * 16);
case NONE -> pacmanPos;
default -> throw new IllegalStateException("Illegal direction");
};
}
}