diff --git a/src/main/java/se/urmo/game/collision/CollisionChecker.java b/src/main/java/se/urmo/game/collision/CollisionChecker.java index 8b0b1b8..194e1a8 100644 --- a/src/main/java/se/urmo/game/collision/CollisionChecker.java +++ b/src/main/java/se/urmo/game/collision/CollisionChecker.java @@ -2,6 +2,7 @@ package se.urmo.game.collision; import lombok.extern.slf4j.Slf4j; +import se.urmo.game.entities.MyPoint; import se.urmo.game.main.GamePanel; import se.urmo.game.util.Direction; import se.urmo.game.map.GameMap; @@ -19,52 +20,89 @@ public class CollisionChecker { this.map = map; } - public Point getValidDestination(Direction direction, Point position, int agent_width, int agent_height) { - List boundaries = switch (direction) { +// public Point getValidDestination(Direction direction, Point position, int agent_width, int agent_height) { +// List boundaries = switch (direction) { +// case NONE -> Collections.emptyList(); +// case RIGHT, LEFT -> List.of( +// new Point(position.x + (direction.dx * agent_width/2), position.y - agent_height/2), +// new Point(position.x + (direction.dx * agent_width/2), position.y + agent_height/2) +// ); +// case UP, DOWN -> List.of( +// new Point(position.x - agent_width/2, position.y + (direction.dy * agent_height/2)), +// new Point(position.x + agent_width/2, position.y + (direction.dy * agent_height/2)) +// ); +// }; +// +// List bs = boundaries.stream().map(p -> new Pair(p.x, p.y, GameMap.screenToRow(p.y), GameMap.screenToCol(p.x))).toList(); +// log.debug("{} boundaries for {} are {}", direction, position, bs); +// +// List normalized = boundaries.stream() +// .map(p -> normalizePosition(direction, p, agent_width, agent_height)) +// .toList(); +// +// if (map.isPassable(normalized)) { +// return normalizePosition(direction, position, agent_width, agent_height); +// } +// return null; // Blocked +// } + +// /** +// * Applies specific rules to movement +// * This, for instance, makes sure the tunnel left/right works. +// * +// * @param dir +// * @param pos +// * @param agent_width +// * @param agent_height +// * @return +// */ +// public Point normalizePosition(Direction dir, Point pos, int agent_width, int agent_height) { +// int x = pos.x; +// int y = pos.y; +// int width = GamePanel.SCREEN_WIDTH; +// int height = GamePanel.SCREEN_HEIGHT; +// +// // tunnel +// if (x < GameMap.OFFSET_X) x = width - agent_width/2 - GameMap.OFFSET_X; // right +// if (x >= (width - GameMap.OFFSET_X)) x = GameMap.OFFSET_X; // left +// +// return new Point(x, y); +// } + + public MyPoint getValidDestination(Direction direction, MyPoint position, int agent_width, int agent_height) { + List boundaries = switch (direction) { case NONE -> Collections.emptyList(); case RIGHT, LEFT -> List.of( - new Point(position.x + (direction.dx * agent_width/2), position.y - agent_height/2), - new Point(position.x + (direction.dx * agent_width/2), position.y + agent_height/2) + new MyPoint(position.x + (direction.dx * agent_width/2), position.y - agent_height/2), + new MyPoint(position.x + (direction.dx * agent_width/2), position.y + agent_height/2) ); case UP, DOWN -> List.of( - new Point(position.x - agent_width/2, position.y + (direction.dy * agent_height/2)), - new Point(position.x + agent_width/2, position.y + (direction.dy * agent_height/2)) + new MyPoint(position.x - agent_width/2, position.y + (direction.dy * agent_height/2)), + new MyPoint(position.x + agent_width/2, position.y + (direction.dy * agent_height/2)) ); }; - List bs = boundaries.stream().map(p -> new Pair(p.x, p.y, GameMap.screenToRow(p.y), GameMap.screenToCol(p.x))).toList(); - log.debug("{} boundaries for {} are {}", direction, position, bs); - - List normalized = boundaries.stream() - .map(p -> normalizePosition(direction, p, agent_width, agent_height)) + List normalized = boundaries.stream() + .map(p -> normalizePosition(direction, p.x, p.y, agent_width, agent_height)) .toList(); - if (map.isPassable(normalized)) { - return normalizePosition(direction, position, agent_width, agent_height); + boolean passable = normalized.stream().allMatch(myPoint -> map.isPassable((int) myPoint.x, (int) myPoint.y)); + if (passable) { + return normalizePosition(direction, position.x, position.y, agent_width, agent_height); } return null; // Blocked } - /** - * Applies specific rules to movement - * This, for instance, makes sure the tunnel left/right works. - * - * @param dir - * @param pos - * @param agent_width - * @param agent_height - * @return - */ - public Point normalizePosition(Direction dir, Point pos, int agent_width, int agent_height) { - int x = pos.x; - int y = pos.y; + private MyPoint normalizePosition(Direction direction, double x, double y, int agent_width, int agent_height) { + double x1 = x; + double y1 = y; int width = GamePanel.SCREEN_WIDTH; int height = GamePanel.SCREEN_HEIGHT; // tunnel - if (x < GameMap.OFFSET_X) x = width - agent_width/2 - GameMap.OFFSET_X; // right - if (x >= (width - GameMap.OFFSET_X)) x = GameMap.OFFSET_X; // left + if (x < GameMap.OFFSET_X) x1 = width - agent_width/2 - GameMap.OFFSET_X; // right + if (x>= (width - GameMap.OFFSET_X)) x1 = GameMap.OFFSET_X; // left - return new Point(x, y); + return new MyPoint(x1, y1); } } diff --git a/src/main/java/se/urmo/game/entities/MyPoint.java b/src/main/java/se/urmo/game/entities/MyPoint.java new file mode 100644 index 0000000..af2eb19 --- /dev/null +++ b/src/main/java/se/urmo/game/entities/MyPoint.java @@ -0,0 +1,34 @@ +package se.urmo.game.entities; + +public class MyPoint { + public final double x; + public final double y; + + public MyPoint(double x, double y) { + this.x = x; + this.y = y; + } + + @Override + public String toString() { + return "MyPoint{" + + "x=" + x + + ", y=" + y + + '}'; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + + MyPoint myPoint = (MyPoint) o; + return Double.compare(x, myPoint.x) == 0 && Double.compare(y, myPoint.y) == 0; + } + + @Override + public int hashCode() { + int result = Double.hashCode(x); + result = 31 * result + Double.hashCode(y); + return result; + } +} diff --git a/src/main/java/se/urmo/game/entities/PacMan.java b/src/main/java/se/urmo/game/entities/PacMan.java index ff19be0..63b3909 100644 --- a/src/main/java/se/urmo/game/entities/PacMan.java +++ b/src/main/java/se/urmo/game/entities/PacMan.java @@ -22,16 +22,16 @@ public class PacMan { private static final int COLLISION_BOX_SIZE = 16; private static final int COLLISION_BOX_OFFSET = (PACMAN_SIZE - COLLISION_BOX_SIZE) / 2; private final Game game; - private final Point startPosition; + //private final Point startPosition; + private final MyPoint startPosition; private int aniTick = 0; private int aniIndex = 0; private static final int ANIMATION_UPDATE_FREQUENCY = 10; - private int speed = 1; + private static final double BASE_SPEED = 0.40; @Setter private boolean moving; private final BufferedImage[][] movmentImages = new BufferedImage[4][4]; - @Getter - private Point position; + private MyPoint position; private static final BufferedImage COLLISION_BOX = MiscUtil.createOutlinedBox(COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, Color.yellow, 2); private final CollisionChecker collisionChecker; @Setter @@ -41,9 +41,9 @@ public class PacMan { public PacMan(Game game, CollisionChecker collisionChecker) { this.game = game; this.collisionChecker = collisionChecker; - this.position = new Point( + this.position = new MyPoint( 26 * GameMap.MAP_TILESIZE + GameMap.OFFSET_X, - 13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + (GameMap.MAP_TILESIZE / 2)); + 13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + ((double) GameMap.MAP_TILESIZE / 2)); this.startPosition = this.position; loadAnimation(); } @@ -72,8 +72,8 @@ public class PacMan { public void draw(Graphics g) { g.drawImage( movmentImages[direction==Direction.NONE ? 0 : direction.ordinal()][aniIndex], - position.x - PACMAN_OFFSET, - position.y - PACMAN_OFFSET, + (int) position.x - PACMAN_OFFSET, + (int) position.y - PACMAN_OFFSET, PACMAN_SIZE, PACMAN_SIZE, null); //g.drawImage(COLLISION_BOX, position.x - COLLISION_BOX_OFFSET, position.y - COLLISION_BOX_OFFSET, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, null); @@ -84,15 +84,16 @@ public class PacMan { public void update() { updateAnimationTick(); if(moving) { - Point newPosition = switch (direction) { - case RIGHT -> new Point(position.x + speed, position.y); - case LEFT -> new Point(position.x - speed, position.y); - case UP -> new Point(position.x, position.y - speed); - case DOWN -> new Point(position.x, position.y + speed); + log.debug("Moving to {}", direction); + MyPoint mpoint = switch (direction) { + case RIGHT -> new MyPoint(position.x + getSpeed(), position.y); + case LEFT -> new MyPoint(position.x - getSpeed(), position.y); + case UP -> new MyPoint(position.x, position.y - getSpeed()); + case DOWN -> new MyPoint(position.x, position.y + getSpeed()); default -> throw new IllegalStateException("Unexpected value: " + direction); }; - log.debug("At: {},trying to move {} to {}", position, direction.name(), newPosition); - Point destination = collisionChecker.getValidDestination(direction, newPosition, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE); + + MyPoint destination = collisionChecker.getValidDestination(direction, mpoint, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE); if (destination != null) { position = destination; @@ -100,6 +101,10 @@ public class PacMan { } } + private double getSpeed() { + return BASE_SPEED * 0.8; + } + private void updateAnimationTick() { if (moving) { aniTick++; @@ -115,7 +120,7 @@ public class PacMan { } public double distanceTo(Point point) { - return position.distance(point); + return new Point((int) position.x, (int) position.y).distance(point); } public void loseLife() { @@ -131,6 +136,10 @@ public class PacMan { } public Rectangle getBounds() { - return new Rectangle(position.x - COLLISION_BOX_OFFSET, position.y - COLLISION_BOX_OFFSET, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE); + return new Rectangle((int) (position.x - COLLISION_BOX_OFFSET), (int) (position.y - COLLISION_BOX_OFFSET), COLLISION_BOX_SIZE, COLLISION_BOX_SIZE); + } + + public Point getPosition() { + return new Point((int) position.x, (int) position.y); } }