diff options
Diffstat (limited to 'pacman/model/src/main/java')
5 files changed, 184 insertions, 75 deletions
diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/Board.java b/pacman/model/src/main/java/com/gr15/pacman/model/Board.java index 41595c4..898ec3b 100644 --- a/pacman/model/src/main/java/com/gr15/pacman/model/Board.java +++ b/pacman/model/src/main/java/com/gr15/pacman/model/Board.java @@ -10,7 +10,6 @@ public class Board { private int width; public enum TileType { WALL, EMPTY }; - public enum Direction { UP, DOWN, LEFT, RIGHT, NONE }; public Board(int height, int width) { this.width = width; diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java b/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java index 728fbd2..990fb15 100644 --- a/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java +++ b/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java @@ -3,7 +3,7 @@ package com.gr15.pacman.model; import java.util.HashMap; import java.util.Map; -import com.gr15.pacman.model.Board.Direction; +import com.gr15.pacman.model.entities.Entity.Direction; import com.gr15.pacman.model.Board.TileType; import com.gr15.pacman.model.entities.Entity; import com.gr15.pacman.model.entities.Pacman; diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/Position.java b/pacman/model/src/main/java/com/gr15/pacman/model/Position.java index c492628..15c567a 100644 --- a/pacman/model/src/main/java/com/gr15/pacman/model/Position.java +++ b/pacman/model/src/main/java/com/gr15/pacman/model/Position.java @@ -2,7 +2,7 @@ package com.gr15.pacman.model; import java.util.List; -import com.gr15.pacman.model.Board.Direction; +import com.gr15.pacman.model.entities.Entity.Direction; /** * Position diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/entities/Entity.java b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Entity.java index 395a170..daf0eef 100644 --- a/pacman/model/src/main/java/com/gr15/pacman/model/entities/Entity.java +++ b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Entity.java @@ -13,6 +13,8 @@ public abstract class Entity { private float subTileY = 0.0f; private double radius; + + public enum Direction { UP, DOWN, LEFT, RIGHT, NONE }; public Entity(Position startPos, double radius) { this.radius = radius; diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/entities/Pacman.java b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Pacman.java index 5d9cf22..cb15b06 100644 --- a/pacman/model/src/main/java/com/gr15/pacman/model/entities/Pacman.java +++ b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Pacman.java @@ -2,25 +2,50 @@ package com.gr15.pacman.model.entities; import com.gr15.pacman.model.Board; import com.gr15.pacman.model.Position; -import com.gr15.pacman.model.Board.Direction; /** - * Pacman + * Represents the Pacman character in the game. + * Handles movement logic including direction changes, wall collisions, + * snapping to tile centers, and updating position on the game board. */ public class Pacman extends Entity { - /* Tiles per second */ + /* Javadoc for attributes, + * since movement is a little complex */ + + /** Movement speed in tiles per second. */ private double speed; + + /** Current direction of movement. */ private Direction currentDirection = Direction.NONE; + + /** Desired direction to change to, if possible. */ private Direction nextDirection; + /** + * Constructs a new Pacman instance. + * + * @param startPos the starting tile {@link Position} of Pacman. + * @param speed the movement speed in tiles per second. + * @param startDir the initial movement {@link Direction}. + * @param radius the radius of Pacman collision. + */ public Pacman(Position startPos, double speed, Direction startDir, double radius) { super(startPos, radius); this.speed = speed; this.nextDirection = startDir; } + /** + * Updates Pacman's {@link Position} based on the time elapsed + * and the game {@link Board} state. + * Handles turning, snapping to tile center, + * and tile boundary transitions. + * + * @param board the game {@link Board}, used to determine valid movement. + * @param deltaSeconds time in seconds since the last update in seconds. + */ @Override public void move(Board board, double deltaSeconds) { float subTileX = super.getSubTileX(); @@ -28,118 +53,201 @@ public class Pacman double distanceToMove = speed * deltaSeconds; Position currentPos = super.getPosition(); - boolean canMoveNext = nextDirection != Direction.NONE - && board.isMovable(currentPos.offset(nextDirection)); - boolean canContinue = currentDirection != Direction.NONE - && board.isMovable(currentPos.offset(currentDirection)); - - Direction direction = canMoveNext ? nextDirection - : (canContinue ? currentDirection : Direction.NONE); + boolean canMoveNext = canMove(board, currentPos, nextDirection); + boolean canContinue = canMove(board, currentPos, currentDirection); + Direction direction = decideDirection(canMoveNext, canContinue); if (direction == Direction.NONE) { - /* Snap to center if not moving */ - double centerX = 0.5; - double centerY = 0.5; - double distToCenterX = Math.abs(subTileX - centerX); - double distToCenterY = Math.abs(subTileY - centerY); - - if (distToCenterX < distanceToMove) { - subTileX = (float)centerX; - } else { - subTileX += (subTileX < centerX ? 1 : -1) * distanceToMove; - } - - if (distToCenterY < distanceToMove) { - subTileY = (float)centerY; - } else { - subTileY += (subTileY < centerY ? 1 : -1) * distanceToMove; - } - - super.setSubTileX(subTileX); - super.setSubTileY(subTileY); - return; + snapToCenter(distanceToMove); + return; /* Returning early, since no more updating required */ } - boolean verticalMove = direction == Direction.UP - || direction == Direction.DOWN; - int directionSign = (direction == Direction.UP - || direction == Direction.LEFT) ? -1 : 1; + boolean verticalMove = isVertical(direction); + int directionSign = getDirectionSign(direction); + + double subPrimary = verticalMove ? subTileY : subTileX; + double subSecondary = verticalMove ? subTileX : subTileY; - /* Determine primary and secondary sub-tile axes */ - double subTilePrimary = verticalMove ? subTileY : subTileX; - double subTileSecondary = verticalMove ? subTileX : subTileY; - double center = Math.floor(subTileSecondary) + 0.5; - double distanceToCenter = Math.abs(subTileSecondary - center); + double center = Math.floor(subSecondary) + 0.5; + double distanceToCenter = Math.abs(subSecondary - center); - /* First, move to center if needed */ + /* Snap to secondary axis center first */ if (distanceToCenter > 0.01) { double moveToCenter = Math.min(distanceToMove, distanceToCenter); - if (subTileSecondary < center) { - subTileSecondary += moveToCenter; - } else { - subTileSecondary -= moveToCenter; - } + subSecondary += (subSecondary < center ? 1 : -1) * moveToCenter; distanceToMove -= moveToCenter; } - /* Apply secondary axis back */ + /* Storing new secondry axis sub-tile position */ if (verticalMove) { - subTileX = (float)subTileSecondary; + subTileX = (float)subSecondary; } else { - subTileY = (float)subTileSecondary; + subTileY = (float)subSecondary; } - /* Now, attempt to move along primary axis */ while (distanceToMove > 0.0001) { - double maxStep = directionSign > 0 ? 1.0 - subTilePrimary - : subTilePrimary; + /* Capping movement distance to a single tile */ + double maxStep = directionSign > 0 ? 1.0 - subPrimary : subPrimary; double step = Math.min(distanceToMove, maxStep); - double newSubTilePrimary = subTilePrimary + directionSign * step; - + double newSubPrimary = subPrimary + directionSign * step; - if ((direction == Direction.RIGHT && newSubTilePrimary >= 1.0) - || (direction == Direction.LEFT && newSubTilePrimary <= 0.0) - || (direction == Direction.DOWN && newSubTilePrimary >= 1.0) - || (direction == Direction.UP && newSubTilePrimary <= 0.0)) { - - Position newPos = currentPos.offset(direction); - if (board.isMovable(newPos)) { - currentPos = newPos; - subTilePrimary = directionSign > 0 ? 0.0 : 1.0; + if (crossedTileBoundary(direction, newSubPrimary)) { + Position nextPos = currentPos.offset(direction); + if (board.isMovable(nextPos)) { + currentPos = nextPos; + subPrimary = directionSign > 0 ? 0.0 : 1.0; } else { currentDirection = Direction.NONE; - subTilePrimary = directionSign > 0 ? 1.0 : 0.0; - break; + subPrimary = directionSign > 0 ? 1.0 : 0.0; + break; /* stopping at wall */ } } else { - subTilePrimary = newSubTilePrimary; + subPrimary = newSubPrimary; } + /* If there's still longer to go */ distanceToMove -= step; } - /* Assign back primary axis */ + /* Storing primary axis sub-tile position */ if (verticalMove) { - subTileY = (float)subTilePrimary; + subTileY = (float)subPrimary; } else { - subTileX = (float)subTilePrimary; + subTileX = (float)subPrimary; } - /* Update direction state */ + /* If hit wall, set direction to none */ if (canMoveNext) { currentDirection = nextDirection; nextDirection = Direction.NONE; } - /* Update final state */ + /* Setting new position */ super.setSubTileX(subTileX); super.setSubTileY(subTileY); super.setPosition(currentPos); } - /* Getters and setters */ + /** + * Helper function that determines if Pacman can move + * in the specified direction. + * + * @param board the game {@link Board}. + * @param pos the current {@link Position}. + * @param dir the direction to check. + * @return true if the tile in the given {@link Direction} is movable. + */ + private boolean canMove(Board board, Position pos, Direction dir) { + return dir != Direction.NONE && board.isMovable(pos.offset(dir)); + } + + /** + * Helper function that decides the direction to move in + * based on current and next direction availability. + * + * @param canMoveNext true if the next direction is available. + * @param canContinue true if continuing in the current direction is possible. + * @return the direction Pacman should move in. + */ + private Direction decideDirection(boolean canMoveNext, boolean canContinue) { + if (canMoveNext) { return nextDirection; } + if (canContinue) { return currentDirection; } + return Direction.NONE; + } + + /** + * helper function that checks if a direction is vertical. + * + * @param dir the direction to check. + * @return true if the direction is {@link Direction.UP} or {@link Direction.DOWN}. + */ + private boolean isVertical(Direction dir) { + return dir == Direction.UP || dir == Direction.DOWN; + } + + /** + * Helper function that gets the sign of movement for a {@link Direction}. + * + * @param dir the direction. + * @return -1 for UP or LEFT and 1 for DOWN or RIGHT. + */ + private int getDirectionSign(Direction dir) { + return (dir == Direction.UP || dir == Direction.LEFT) ? -1 : 1; + } + + /** + * Helper function that determines if Pacman has crossed a tile boundary. + * + * @param dir the direction of movement. + * @param newPrimary the new sub-tile coordinate in the movement axis. + * @return true if a tile boundary was crossed. + */ + private boolean crossedTileBoundary(Direction dir, double newPrimary) { + return (dir == Direction.UP && newPrimary <= 0.0) + || (dir == Direction.DOWN && newPrimary >= 1.0) + || (dir == Direction.LEFT && newPrimary <= 0.0) + || (dir == Direction.RIGHT && newPrimary >= 1.0); + } + + /** + * Helper function that snaps Pacman toward the center of the tile when not moving. + * + * @param distanceToMove the maximum distance Pacman can move. + */ + private void snapToCenter(double distanceToMove) { + float subTileX = super.getSubTileX(); + float subTileY =super.getSubTileY(); + double center = 0.5; + + subTileX = (float)snapAxisToCenter(subTileX, center, distanceToMove); + subTileY = (float)snapAxisToCenter(subTileY, center, distanceToMove); + + super.setSubTileX(subTileX); + super.setSubTileY(subTileY); + } + + /** + * Helper function that moves a sub-tile coordinate toward the center up to a maximum distance. + * + * @param sub the current sub-coordinate. + * @param center the center coordinate (typically 0.5). + * @param maxMove the maximum movement allowed. + * @return the updated coordinate. + */ + private double snapAxisToCenter(double sub, double center, double maxMove) { + double dist = Math.abs(sub - center); + if (dist < maxMove) { + return center; + } else { + return sub + ((sub < center) ? 1 : -1) * maxMove; + } + } + + /** + * Gets the current speed of Pacman. + * + * @return the speed in tiles per second. + */ public double getSpeed() { return this.speed; } + + /** + * Gets the current movement direction of Pacman. + * + * @return the current {@link Direction}. + */ public Direction getDirection() { return this.currentDirection; } + + /** + * Sets a new speed for Pacman. + * + * @param newSpeed the new speed value in tiles per second. + */ public void setSpeed(double newSpeed) { this.speed = newSpeed; } + + /** + * Requests Pacman to change direction at the next available opportunity. + * + * @param newDir the desired direction. + */ public void setDirection(Direction newDir) { this.nextDirection = newDir; } } |