From 4638484b979508f8374d9250b60dd7e8db4f83e7 Mon Sep 17 00:00:00 2001 From: Urban Modig Date: Wed, 3 Sep 2025 00:18:27 +0200 Subject: [PATCH] Refactor CollisionChecker for cleaner boundary handling Streamlined collision logic by introducing helper methods for boundary calculations and movement validation. Replaced commented-out code with efficient implementations, improving readability and maintainability. Added clear documentation for new methods to better convey their purpose and usage. --- .../urmo/game/collision/CollisionChecker.java | 138 ++++++++---------- 1 file changed, 63 insertions(+), 75 deletions(-) diff --git a/src/main/java/se/urmo/game/collision/CollisionChecker.java b/src/main/java/se/urmo/game/collision/CollisionChecker.java index 4095a79..b413afb 100644 --- a/src/main/java/se/urmo/game/collision/CollisionChecker.java +++ b/src/main/java/se/urmo/game/collision/CollisionChecker.java @@ -2,105 +2,93 @@ package se.urmo.game.collision; import lombok.extern.slf4j.Slf4j; -import se.urmo.game.util.MyPoint; import se.urmo.game.main.GamePanel; -import se.urmo.game.util.Direction; import se.urmo.game.map.GameMap; +import se.urmo.game.util.Direction; +import se.urmo.game.util.MyPoint; import java.util.Collections; import java.util.List; @Slf4j public class CollisionChecker { - private GameMap map; + private final GameMap map; public CollisionChecker(GameMap map) { this.map = map; } -// 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 -// } + public MyPoint getValidDestination(Direction direction, MyPoint position, int agentWidth, int agentHeight) { + List boundaries = getBoundariesForDirection(direction, position, agentWidth / 2, agentHeight / 2); -// /** -// * 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); -// } + return canMoveInDirection(agentWidth, boundaries) + ? normalizePosition(position, agentWidth) + : null; // Blocked + } - public MyPoint getValidDestination(Direction direction, MyPoint position, int agent_width, int agent_height) { - List boundaries = switch (direction) { + /** + * Determines whether boundaries (corners) are in a passible i.e., not blocked, position + * + * @param agentWidth The width of the entity attempting to move. + * @param boundaries The boundary points representing the edges of the area occupied by the entity. + * @return {@code true} if movement in the specified direction is possible; {@code false} otherwise. + */ + private boolean canMoveInDirection(int agentWidth, List boundaries) { + return boundaries.stream() + .map(boundary -> normalizePosition(boundary, agentWidth)) + .allMatch(myPoint -> map.isPassable((int) myPoint.x, (int) myPoint.y)); + } + + /** + * Calculates the boundary points of a given position based on a specified direction + * and horizontal and vertical offsets. The resulting boundaries represent the edges + * of the area occupied by the entity moving in the specified direction. + * + * @param direction The direction of movement (e.g., UP, DOWN, LEFT, RIGHT, or NONE). + * @param position The current position represented as a {@code MyPoint}. + * @param horizontalOffset The horizontal offset to determine the boundary width. + * @param verticalOffset The vertical offset to determine the boundary height. + * @return A list of boundary points in the form of {@code MyPoint} objects. If the + * direction is {@code NONE}, an empty list is returned. + */ + private static List getBoundariesForDirection(Direction direction, MyPoint position, int horizontalOffset, int verticalOffset) { + return switch (direction) { case NONE -> Collections.emptyList(); case RIGHT, LEFT -> List.of( - 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) + new MyPoint(position.x + ((double) (direction.dx * horizontalOffset) / 2), position.y - (double) verticalOffset / 2), + new MyPoint(position.x + ((double) (direction.dx * horizontalOffset) / 2), position.y + (double) verticalOffset / 2) ); case UP, DOWN -> List.of( - 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)) + new MyPoint(position.x - (double) horizontalOffset / 2, position.y + ((double) (direction.dy * verticalOffset) / 2)), + new MyPoint(position.x + (double) horizontalOffset / 2, position.y + ((double) (direction.dy * verticalOffset) / 2)) ); }; + } - List normalized = boundaries.stream() - .map(p -> normalizePosition(direction, p.x, p.y, agent_width, agent_height)) - .toList(); - - 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); + /** + * Normalizes the position of an agent when it reaches screen boundaries, + * implementing tunnel-like behavior when crossing horizontal boundaries. + * + * @param position The current position to normalize + * @param agentWidth The width of the agent + * @return Normalized position as MyPoint + */ + private MyPoint normalizePosition(MyPoint position, int agentWidth) { + if (isLeftBoundary(position.x)) { + return new MyPoint(GamePanel.SCREEN_WIDTH - (double) agentWidth / 2 - GameMap.OFFSET_X, position.y); } - return null; // Blocked + if (isRightBoundary(position.x)) { + return new MyPoint(GameMap.OFFSET_X, position.y); + } + return position; } - 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) x1 = width - agent_width/2 - GameMap.OFFSET_X; // right - if (x>= (width - GameMap.OFFSET_X)) x1 = GameMap.OFFSET_X; // left - - return new MyPoint(x1, y1); + private boolean isLeftBoundary(double x) { + return x < GameMap.OFFSET_X; } + + private boolean isRightBoundary(double x) { + return x >= (GamePanel.SCREEN_WIDTH - GameMap.OFFSET_X); + } + }