Added Scatter-strategy

This commit is contained in:
Urban Modig
2025-08-19 21:17:36 +02:00
parent 64dcba2584
commit 9f316e5b43
13 changed files with 183 additions and 80 deletions

View File

@ -11,7 +11,11 @@ import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class Ghost {
@ -30,22 +34,25 @@ public class Ghost {
private boolean moving = true;
private int aniTick = 0;
private int aniIndex = 0;
private final GhostStrategy scaterStrategy;
private GhostStrategy currentStrategy;
private final BufferedImage[] animation;
private int movementTick = 0;
private Direction direction;
private Direction prevDirection;
private GhostMode mode;
private GhostStrategy currentStrategy;
public Ghost(GhostCollisionChecker collisionChecker, GhostStrategy strategy, BufferedImage[] animation) {
public Ghost(GhostCollisionChecker collisionChecker, GhostStrategy strategy, GhostStrategy scaterStrategy, BufferedImage[] animation) {
this.collisionChecker = collisionChecker;
this.chaseStrategy = strategy;
this.currentStrategy = strategy;
this.scaterStrategy = scaterStrategy;
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);
this.currentStrategy = chaseStrategy;
}
public void draw(Graphics g) {
@ -62,20 +69,19 @@ public class Ghost {
COLLISION_BOX_SIZE, null);
}
public void update(PacMan pacman) {
public void update(PacMan pacman, GameMap map) {
updateAnimationTick();
updatePosition(pacman);
updatePosition(pacman, map);
}
private void updatePosition(PacMan pacman) {
private void updatePosition(PacMan pacman, GameMap map) {
if (movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) {
if (isAlligned(position)) {
log.info("Evaluating possible directions");
prevDirection = direction;
direction = chooseDirection(
collisionChecker.calculateDirectionAlternatives(position),
currentStrategy.chooseTarget(pacman),
prevDirection);
prioritize(collisionChecker.calculateDirectionAlternatives(position)),
currentStrategy.chooseTarget(pacman, map));
log.info("selecting direction {}", direction);
}
@ -93,17 +99,36 @@ public class Ghost {
} else movementTick++;
}
private Map<Direction, Integer> prioritize(List<Direction> directions) {
return directions.stream()
.filter(d -> d != Direction.NONE)
.collect(Collectors.toMap(
d -> d,
d -> (prevDirection != null && d == prevDirection.opposite()) ? 2 : 1
));
}
private boolean isAlligned(Point pos) {
int row = pos.x % GameMap.MAP_TILESIZE;
int col = pos.y % GameMap.MAP_TILESIZE;
return row == GameMap.MAP_TILESIZE / 2 && col == GameMap.MAP_TILESIZE / 2;
}
private Direction chooseDirection(List<Direction> options, Point target, Direction prevDirection) {
List<Direction> l = options.stream()
// remove any option to go back
.filter(d -> !(prevDirection != null && d.equals(prevDirection.opposite())))
private Direction chooseDirection(Map<Direction, Integer> options, Point target) {
// Find the lowest priority
int lowestPriority = options.values().stream()
.mapToInt(Integer::intValue)
.min()
.orElse(Integer.MAX_VALUE);
// Return all directions that have this priority
List<Direction> l = options.entrySet().stream()
.filter(entry -> entry.getValue() == lowestPriority)
.map(Map.Entry::getKey)
.toList();
Direction best = l.getFirst();
double bestDist = Double.MAX_VALUE;
@ -137,7 +162,7 @@ public class Ghost {
this.mode = mode;
switch (mode) {
case CHASE -> currentStrategy = chaseStrategy;
case SCATTER -> currentStrategy = null;
case SCATTER -> currentStrategy = scaterStrategy;
case FRIGHTENED -> currentStrategy = null;
case EATEN -> currentStrategy = null;
}