136 lines
4.9 KiB
Java
136 lines
4.9 KiB
Java
package se.urmo.game.entities;
|
|
|
|
import se.urmo.game.collision.GhostCollisionChecker;
|
|
import se.urmo.game.main.Game;
|
|
import se.urmo.game.map.GameMap;
|
|
import se.urmo.game.util.Direction;
|
|
import se.urmo.game.util.LoadSave;
|
|
import se.urmo.game.util.MiscUtil;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Graphics;
|
|
import java.awt.Point;
|
|
import java.awt.image.BufferedImage;
|
|
import java.util.List;
|
|
|
|
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;
|
|
private static final int ANIMATION_UPDATE_FREQUENCY = 25;
|
|
private static final int COLLISION_BOX_OFFSET = (GHOST_SIZE - 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 Point position;
|
|
|
|
private boolean moving = true;
|
|
private int aniTick = 0;
|
|
private int aniIndex = 0;
|
|
private BufferedImage[] animation;
|
|
private Direction direction = Direction.LEFT;
|
|
private int movementTick = 0;
|
|
|
|
|
|
public Ghost(Game game, GhostCollisionChecker collisionChecker, GhostStrategy strategy) {
|
|
this.game = game;
|
|
this.collisionChecker = collisionChecker;
|
|
position = new Point(13 * 16 + 8 + GameMap.OFFSET_X, 4 * 16 + 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) {
|
|
g.drawImage(
|
|
animation[aniIndex],
|
|
position.x - COLLISION_BOX_OFFSET,
|
|
position.y - COLLISION_BOX_OFFSET,
|
|
GHOST_SIZE,
|
|
GHOST_SIZE, null);
|
|
g.drawImage(COLLISION_BOX, position.x, position.y, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, null);
|
|
}
|
|
|
|
public void update() {
|
|
updateAnimationTick();
|
|
if(movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) {
|
|
// if intersection - decide direction
|
|
// else if direction isPassible
|
|
List<Direction> i = collisionChecker.isIntersection(position);
|
|
if(!i.isEmpty()){
|
|
// Change direction
|
|
if(i.contains(Direction.DOWN)) direction = Direction.DOWN;
|
|
else if(i.contains(Direction.RIGHT)) direction = Direction.RIGHT;
|
|
else if(i.contains(Direction.UP)) direction = Direction.UP;
|
|
else direction = Direction.LEFT;
|
|
|
|
}
|
|
|
|
//Point target = strategy.chooseTarget(pacman, this, blinky);
|
|
|
|
Point newPosition = switch (direction){
|
|
case RIGHT -> new Point(position.x += GHOST_SPEED, position.y);
|
|
case LEFT -> new Point(position.x -= GHOST_SPEED, position.y);
|
|
case DOWN -> new Point(position.x, position.y += GHOST_SPEED);
|
|
case UP -> new Point(position.x, position.y -= GHOST_SPEED);
|
|
default -> throw new IllegalStateException("Illegal direction");
|
|
};
|
|
|
|
Point destination = collisionChecker.getValidDestination(direction, newPosition, GHOST_SIZE, GHOST_SIZE);
|
|
|
|
// if (position.x + direction.dx * GHOST_SPEED < GameMap.OFFSET_X) direction = direction.opposite();
|
|
// if (position.x + GHOST_SIZE + (direction.dx * GHOST_SPEED) > GamePanel.SCREEN_WIDTH - GameMap.OFFSET_X)
|
|
// direction = direction.opposite();
|
|
|
|
if(destination != null) {
|
|
position = destination;
|
|
}
|
|
movementTick = 0;
|
|
} else movementTick++;
|
|
}
|
|
|
|
private Direction chooseDirection(List<Direction> options, Point target) {
|
|
Direction best = options.get(0);
|
|
double bestDist = Double.MAX_VALUE;
|
|
|
|
for (Direction d : options) {
|
|
int nx = position.x + d.dx * GameMap.MAP_TILESIZE;
|
|
int ny = position.y + d.dy * GameMap.MAP_TILESIZE;
|
|
double dist = target.distance(nx, ny);
|
|
if (dist < bestDist) {
|
|
bestDist = dist;
|
|
best = d;
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
|
|
private void updateAnimationTick() {
|
|
if (moving) {
|
|
aniTick++;
|
|
if (aniTick >= ANIMATION_UPDATE_FREQUENCY) {
|
|
aniTick = 0;
|
|
aniIndex++;
|
|
if (aniIndex >= 3) {
|
|
aniIndex = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|