Refactored ghost movement - second rev
This commit is contained in:
@ -16,56 +16,15 @@ public class GhostCollisionChecker {
|
|||||||
this.map = map;
|
this.map = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point getValidDestination(Direction direction, Point position, int agent_width, int agent_height) {
|
|
||||||
|
|
||||||
List<Point> bounderies = switch (direction) {
|
|
||||||
case RIGHT -> List.of(
|
|
||||||
new Point(position.x + agent_width, position.y), // TOPRIGHT
|
|
||||||
new Point(position.x + agent_width, position.y + agent_height)); // BOTTOMRIGHT
|
|
||||||
case LEFT -> List.of(
|
|
||||||
position, // TOPLEFT
|
|
||||||
new Point(position.x, position.y + agent_height)); // BOTTOMLEFT
|
|
||||||
case UP -> List.of(
|
|
||||||
position, // TOPLEFT
|
|
||||||
new Point(position.x + agent_width, position.y)); // TOPRIGHT
|
|
||||||
case DOWN -> List.of(
|
|
||||||
new Point(position.x, position.y + agent_height), // BOTTOMLEFT
|
|
||||||
new Point(position.x + agent_width, position.y + agent_height)); // BOTTOMRIGHT
|
|
||||||
default -> Collections.EMPTY_LIST;
|
|
||||||
};
|
|
||||||
|
|
||||||
log.debug("{} bounderies for {} are {}", direction, position, bounderies);
|
|
||||||
|
|
||||||
List<Point> normalizedBoundaries = bounderies.stream()
|
|
||||||
.map(p -> normalizePosition(direction, p, agent_width, agent_height))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (! map.isSolid(normalizedBoundaries)) {
|
|
||||||
log.debug("{} is open", direction);
|
|
||||||
return normalizePosition(direction, position, agent_width, agent_height);
|
|
||||||
}{
|
|
||||||
log.debug("{} is blocked", direction);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// Blocked
|
|
||||||
}
|
|
||||||
|
|
||||||
public Point normalizePosition(Direction dir, Point pos, int agent_width, int agent_height) {
|
|
||||||
int x = pos.x;
|
|
||||||
int y = pos.y;
|
|
||||||
int width = map.getWidth();
|
|
||||||
int height = map.getHeight();
|
|
||||||
|
|
||||||
// tunnel
|
|
||||||
if (x < GameMap.OFFSET_X) x = width - agent_width - GameMap.OFFSET_X; // right
|
|
||||||
if (x >= (width - GameMap.OFFSET_X)) x = GameMap.OFFSET_X; // left
|
|
||||||
|
|
||||||
return new Point(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Direction> calculateDirectionAlternatives(Point position) {
|
public List<Direction> calculateDirectionAlternatives(Point position) {
|
||||||
List<Direction> intersection = map.directionAlternatives(position);
|
List<Direction> intersection = map.directionAlternatives(position);
|
||||||
log.info("Possible travel directions: {}", intersection);
|
log.info("Possible travel directions: {}", intersection);
|
||||||
return intersection;
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Point canMoveTo(Direction dir, Point pos) {
|
||||||
|
Point pp = new Point(pos.x + dir.dx * GameMap.MAP_TILESIZE/2, pos.y + dir.dy * GameMap.MAP_TILESIZE/2);
|
||||||
|
|
||||||
|
return ! map.isSolid(pp.x, pp.y) ? pos : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public class Ghost {
|
|||||||
|
|
||||||
private static int GHOST_SIZE = 32;
|
private static int GHOST_SIZE = 32;
|
||||||
private static final int ANIMATION_UPDATE_FREQUENCY = 25;
|
private static final int ANIMATION_UPDATE_FREQUENCY = 25;
|
||||||
private static final int COLLISION_BOX_OFFSET = (GHOST_SIZE - COLLISION_BOX_SIZE) / 2;
|
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 static final BufferedImage COLLISION_BOX = MiscUtil.createOutlinedBox(COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, Color.black, 2);
|
||||||
|
|
||||||
private final Game game;
|
private final Game game;
|
||||||
@ -41,7 +41,9 @@ public class Ghost {
|
|||||||
this.game = game;
|
this.game = game;
|
||||||
this.collisionChecker = collisionChecker;
|
this.collisionChecker = collisionChecker;
|
||||||
this.strategy = strategy;
|
this.strategy = strategy;
|
||||||
position = new Point(13 * 16 + 8 + GameMap.OFFSET_X, 4 * 16 + GameMap.OFFSET_Y);
|
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();
|
loadAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,11 +62,15 @@ public class Ghost {
|
|||||||
public void draw(Graphics g) {
|
public void draw(Graphics g) {
|
||||||
g.drawImage(
|
g.drawImage(
|
||||||
animation[aniIndex],
|
animation[aniIndex],
|
||||||
position.x - COLLISION_BOX_OFFSET,
|
position.x - GHOST_SIZE / 2,
|
||||||
position.y - COLLISION_BOX_OFFSET,
|
position.y - GHOST_SIZE / 2,
|
||||||
GHOST_SIZE,
|
GHOST_SIZE,
|
||||||
GHOST_SIZE, null);
|
GHOST_SIZE, null);
|
||||||
g.drawImage(COLLISION_BOX, position.x, position.y, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, null);
|
g.drawImage(COLLISION_BOX,
|
||||||
|
position.x - COLLISION_BOX_OFFSET,
|
||||||
|
position.y - COLLISION_BOX_OFFSET,
|
||||||
|
COLLISION_BOX_SIZE,
|
||||||
|
COLLISION_BOX_SIZE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(PacMan pacman) {
|
public void update(PacMan pacman) {
|
||||||
@ -74,6 +80,12 @@ public class Ghost {
|
|||||||
|
|
||||||
private void updatePosition(PacMan pacman) {
|
private void updatePosition(PacMan pacman) {
|
||||||
if(movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) {
|
if(movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) {
|
||||||
|
if(!isAlligned(position)){
|
||||||
|
position = align(position);
|
||||||
|
log.debug("Aligned: {}", position);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.info("Evaluating possible directions");
|
log.info("Evaluating possible directions");
|
||||||
Direction intendedDirection = chooseDirection(
|
Direction intendedDirection = chooseDirection(
|
||||||
collisionChecker.calculateDirectionAlternatives(position),
|
collisionChecker.calculateDirectionAlternatives(position),
|
||||||
@ -82,11 +94,10 @@ public class Ghost {
|
|||||||
|
|
||||||
log.info("selecting direction {}", intendedDirection);
|
log.info("selecting direction {}", intendedDirection);
|
||||||
Point newPosition = new Point(
|
Point newPosition = new Point(
|
||||||
position.x += intendedDirection.dx * GHOST_SPEED,
|
position.x + intendedDirection.dx * GHOST_SPEED,
|
||||||
position.y += intendedDirection.dy * GHOST_SPEED);
|
position.y + intendedDirection.dy * GHOST_SPEED);
|
||||||
|
|
||||||
Point destination = collisionChecker.getValidDestination(intendedDirection, newPosition, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE);
|
|
||||||
|
|
||||||
|
Point destination = collisionChecker.canMoveTo(intendedDirection, newPosition);
|
||||||
if(destination != null) {
|
if(destination != null) {
|
||||||
position = destination;
|
position = destination;
|
||||||
}
|
}
|
||||||
@ -94,8 +105,19 @@ public class Ghost {
|
|||||||
} else movementTick++;
|
} else movementTick++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 Point align(Point point){
|
||||||
|
int row = point.x / GameMap.MAP_TILESIZE;
|
||||||
|
int col = point.y / GameMap.MAP_TILESIZE;
|
||||||
|
return new Point(row * GameMap.MAP_TILESIZE + GameMap.MAP_TILESIZE /2, col * GameMap.MAP_TILESIZE + GameMap.MAP_TILESIZE /2);
|
||||||
|
}
|
||||||
|
|
||||||
private Direction chooseDirection(List<Direction> options, Point target) {
|
private Direction chooseDirection(List<Direction> options, Point target) {
|
||||||
Direction best = options.get(0);
|
Direction best = options.getFirst();
|
||||||
double bestDist = Double.MAX_VALUE;
|
double bestDist = Double.MAX_VALUE;
|
||||||
|
|
||||||
for (Direction d : options) {
|
for (Direction d : options) {
|
||||||
|
|||||||
@ -199,7 +199,7 @@ public class GameMap {
|
|||||||
return points.stream().allMatch(p -> isSolid(p.x, p.y));
|
return points.stream().allMatch(p -> isSolid(p.x, p.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSolid(int x, int y) {
|
public boolean isSolid(int x, int y) {
|
||||||
int row = (y - OFFSET_Y) / MAP_TILESIZE;
|
int row = (y - OFFSET_Y) / MAP_TILESIZE;
|
||||||
int col = (x - OFFSET_X) / MAP_TILESIZE;
|
int col = (x - OFFSET_X) / MAP_TILESIZE;
|
||||||
MapTile mapTile = mapData[row][col];
|
MapTile mapTile = mapData[row][col];
|
||||||
|
|||||||
Reference in New Issue
Block a user