diff --git a/pom.xml b/pom.xml index ab15743..efe32ec 100644 --- a/pom.xml +++ b/pom.xml @@ -13,5 +13,24 @@ 21 UTF-8 + + + central + https://repo1.maven.org/maven2/ + + + + + org.projectlombok + lombok + 1.18.30 + provided + + + org.slf4j + slf4j-simple + 2.0.13 + + \ No newline at end of file diff --git a/src/main/java/se/urmo/game/collision/GhostCollisionChecker.java b/src/main/java/se/urmo/game/collision/GhostCollisionChecker.java index e17b530..9a7d68e 100644 --- a/src/main/java/se/urmo/game/collision/GhostCollisionChecker.java +++ b/src/main/java/se/urmo/game/collision/GhostCollisionChecker.java @@ -1,5 +1,6 @@ package se.urmo.game.collision; +import lombok.extern.slf4j.Slf4j; import se.urmo.game.map.GameMap; import se.urmo.game.util.Direction; @@ -7,6 +8,7 @@ import java.awt.Point; import java.util.Collections; import java.util.List; +@Slf4j public class GhostCollisionChecker { private final GameMap map; @@ -32,16 +34,20 @@ public class GhostCollisionChecker { default -> Collections.EMPTY_LIST; }; - System.out.println( direction + " bounderies for " + position + " are " + bounderies); + log.debug("{} bounderies for {} are {}", direction, position, bounderies); List normalizedBoundaries = bounderies.stream() .map(p -> normalizePosition(direction, p, agent_width, agent_height)) .toList(); - if (map.isSolid(normalizedBoundaries)) { + if (! map.isSolid(normalizedBoundaries)) { + log.debug("{} is open", direction); return normalizePosition(direction, position, agent_width, agent_height); + }{ + log.debug("{} is blocked", direction); + return null; } - return null; // Blocked + // Blocked } public Point normalizePosition(Direction dir, Point pos, int agent_width, int agent_height) { @@ -57,9 +63,9 @@ public class GhostCollisionChecker { return new Point(x, y); } - public List isIntersection(Point position) { - List intersection = map.isIntersection(position); - System.out.println("Possible travel directions: " + intersection); + public List calculateDirectionAlternatives(Point position) { + List intersection = map.directionAlternatives(position); + log.info("Possible travel directions: {}", intersection); return intersection; } } diff --git a/src/main/java/se/urmo/game/entities/BlinkyStrategy.java b/src/main/java/se/urmo/game/entities/BlinkyStrategy.java new file mode 100644 index 0000000..d824520 --- /dev/null +++ b/src/main/java/se/urmo/game/entities/BlinkyStrategy.java @@ -0,0 +1,10 @@ +package se.urmo.game.entities; + +import java.awt.Point; + +public class BlinkyStrategy implements GhostStrategy { + @Override + public Point chooseTarget(PacMan pacman, Ghost self, Ghost blinky) { + return pacman.getTilePosition(); + } +} diff --git a/src/main/java/se/urmo/game/entities/Ghost.java b/src/main/java/se/urmo/game/entities/Ghost.java index bfcd150..a10a3ef 100644 --- a/src/main/java/se/urmo/game/entities/Ghost.java +++ b/src/main/java/se/urmo/game/entities/Ghost.java @@ -1,5 +1,6 @@ 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; @@ -13,6 +14,7 @@ import java.awt.Point; import java.awt.image.BufferedImage; import java.util.List; +@Slf4j public class Ghost { private static final int COLLISION_BOX_SIZE = 16; private static final int GHOST_SPEED = 1; @@ -25,19 +27,20 @@ public class Ghost { private final Game game; private final GhostCollisionChecker collisionChecker; + private final GhostStrategy strategy; 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; + this.strategy = strategy; position = new Point(13 * 16 + 8 + GameMap.OFFSET_X, 4 * 16 + GameMap.OFFSET_Y); loadAnimation(); } @@ -64,36 +67,25 @@ public class Ghost { g.drawImage(COLLISION_BOX, position.x, position.y, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, null); } - public void update() { + public void update(PacMan pacman) { updateAnimationTick(); + updatePosition(pacman); + } + + private void updatePosition(PacMan pacman) { if(movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) { - // if intersection - decide direction - // else if direction isPassible - List 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; + log.info("Evaluating possible directions"); + Direction intendedDirection = chooseDirection( + collisionChecker.calculateDirectionAlternatives(position), + strategy.chooseTarget(pacman, null, null)); - } - //Point target = strategy.chooseTarget(pacman, this, blinky); + log.info("selecting direction {}", intendedDirection); + Point newPosition = new Point( + position.x += intendedDirection.dx * GHOST_SPEED, + position.y += intendedDirection.dy * GHOST_SPEED); - 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(); + Point destination = collisionChecker.getValidDestination(intendedDirection, newPosition, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE); if(destination != null) { position = destination; diff --git a/src/main/java/se/urmo/game/entities/GhostStrategy.java b/src/main/java/se/urmo/game/entities/GhostStrategy.java new file mode 100644 index 0000000..6635f01 --- /dev/null +++ b/src/main/java/se/urmo/game/entities/GhostStrategy.java @@ -0,0 +1,7 @@ +package se.urmo.game.entities; + +import java.awt.Point; + +public interface GhostStrategy { + Point chooseTarget(PacMan pacman, Ghost self, Ghost blinky); +} diff --git a/src/main/java/se/urmo/game/entities/PacMan.java b/src/main/java/se/urmo/game/entities/PacMan.java index 46f76bd..8bbd812 100644 --- a/src/main/java/se/urmo/game/entities/PacMan.java +++ b/src/main/java/se/urmo/game/entities/PacMan.java @@ -109,4 +109,8 @@ public class PacMan { public void setDirection(Direction direction) { this.direction = direction; } + + public Point getTilePosition() { + return position; + } } diff --git a/src/main/java/se/urmo/game/map/GameMap.java b/src/main/java/se/urmo/game/map/GameMap.java index 9bdf913..77a401e 100644 --- a/src/main/java/se/urmo/game/map/GameMap.java +++ b/src/main/java/se/urmo/game/map/GameMap.java @@ -1,5 +1,6 @@ package se.urmo.game.map; +import lombok.extern.slf4j.Slf4j; import se.urmo.game.main.GamePanel; import se.urmo.game.util.Direction; import se.urmo.game.util.LoadSave; @@ -13,6 +14,7 @@ import java.util.Objects; import java.util.stream.IntStream; import java.util.stream.Stream; +@Slf4j public class GameMap { public static final int MAP_TILESIZE = 16;// 16px from left public static final int OFFSET_Y = 7 * MAP_TILESIZE; // 160px from top @@ -169,22 +171,28 @@ public class GameMap { if(tile.getValue() == 0) tile.setImage(null); } - public List isIntersection(Point position) { + public List directionAlternatives(Point position) { int row = (position.y - OFFSET_Y) / MAP_TILESIZE; int col = (position.x - OFFSET_X) / MAP_TILESIZE; record DirectionCheck(int rowOffset, int colOffset, Direction direction) {} - + log.debug("At [{}][{}]", row, col); return Stream.of( new DirectionCheck(0, 1, Direction.RIGHT), new DirectionCheck(0, -1, Direction.LEFT), new DirectionCheck(1, 0, Direction.DOWN), new DirectionCheck(-1, 0, Direction.UP) ) - .filter(dc -> !mapData[row + dc.rowOffset][col + dc.colOffset].isSolid()) + .filter(dc -> { + int r = row + dc.rowOffset; + int c = col + dc.colOffset; + MapTile mapTile = mapData[r][c]; + boolean solid = mapTile.isSolid(); + log.debug("[{}][{}] {} is {} ({})", r, c, dc.direction, solid ? "solid" : " not solid", mapTile.getValue()); + return !solid; + }) .map(DirectionCheck::direction) .toList(); - } public boolean isSolid(List points) { @@ -196,7 +204,7 @@ public class GameMap { int col = (x - OFFSET_X) / MAP_TILESIZE; MapTile mapTile = mapData[row][col]; boolean solid = mapTile.isSolid(); - //System.out.println("["+row+"]["+col+"] is " + (solid?"solid":" not solid") + " (" + mapTile.getValue() + ")"); + log.debug("["+row+"]["+col+"] is " + (solid?"solid":" not solid") + " (" + mapTile.getValue() + ")"); return solid; } } diff --git a/src/main/java/se/urmo/game/map/MapTile.java b/src/main/java/se/urmo/game/map/MapTile.java index 402359f..e769faf 100644 --- a/src/main/java/se/urmo/game/map/MapTile.java +++ b/src/main/java/se/urmo/game/map/MapTile.java @@ -1,7 +1,12 @@ package se.urmo.game.map; +import lombok.Getter; +import lombok.Setter; + import java.awt.image.BufferedImage; +@Getter +@Setter public class MapTile { private final int value; private BufferedImage image; @@ -11,14 +16,10 @@ public class MapTile { public MapTile(BufferedImage image, int value) { this.value = value; this.image = image; - this.solid = value != 0; + this.solid = value != 0 && value != 99; this.collisionMask = value != 0 ? createCollisionMask(image) : null; } - public boolean[][] getCollisionMask() { - return collisionMask; - } - private boolean[][] createCollisionMask(BufferedImage img) { if(img == null) return null; int w = img.getWidth(); @@ -33,19 +34,4 @@ public class MapTile { return mask; } - public BufferedImage getImage() { - return this.image; - } - - public boolean isSolid() { - return this.solid; - } - - public void setImage(BufferedImage img) { - this.image = img; - } - - public int getValue() { - return this.value; - } } diff --git a/src/main/java/se/urmo/game/state/PlayingState.java b/src/main/java/se/urmo/game/state/PlayingState.java index f7dcc43..0b5ba85 100644 --- a/src/main/java/se/urmo/game/state/PlayingState.java +++ b/src/main/java/se/urmo/game/state/PlayingState.java @@ -1,7 +1,9 @@ package se.urmo.game.state; +import lombok.Getter; import se.urmo.game.collision.CollisionChecker; import se.urmo.game.collision.GhostCollisionChecker; +import se.urmo.game.entities.BlinkyStrategy; import se.urmo.game.entities.Ghost; import se.urmo.game.entities.PacMan; import se.urmo.game.main.Game; @@ -16,19 +18,20 @@ public class PlayingState implements GameState { private final GameStateManager gameStateManager; private final Ghost ghost; private PacMan pacman; + @Getter private GameMap map; public PlayingState(Game game, GameStateManager gameStateManager) { this.game = game; this.gameStateManager = gameStateManager; this.map = new GameMap(); this.pacman = new PacMan(game, new CollisionChecker(map)); - this.ghost = new Ghost(game, new GhostCollisionChecker(map), null); + this.ghost = new Ghost(game, new GhostCollisionChecker(map), new BlinkyStrategy()); } @Override public void update() { pacman.update(); - ghost.update(); + ghost.update(pacman); } @Override @@ -58,8 +61,4 @@ public class PlayingState implements GameState { pacman.setMoving(false); pacman.setDirection(Direction.NONE); } - - public GameMap getMap() { - return map; - } } diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties new file mode 100644 index 0000000..eafa2b0 --- /dev/null +++ b/src/main/resources/simplelogger.properties @@ -0,0 +1 @@ +org.slf4j.simpleLogger.defaultLogLevel=debug \ No newline at end of file