diff options
Diffstat (limited to '')
11 files changed, 467 insertions, 4 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 new file mode 100644 index 0000000..41595c4 --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/Board.java @@ -0,0 +1,49 @@ +package com.gr15.pacman.model; + +/** + * Board + */ +public class Board { + + private TileType[][] tileBoard; + private int height; + 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; + this.height = height; + } + + public Board(int height, int width, TileType[][] tileBoard) { + this(height, width); + this.tileBoard = tileBoard; + } + + public boolean isMovable(Position pos) { + if (!pos.inBounds(width, height)) { + return false; + } else { + return tileBoard[pos.y()][pos.x()] != TileType.WALL; + } + } + + + /* Getters and setters */ + public TileType[][] getTileBoard() { return this.tileBoard; } + public TileType getTile(int x, int y) { return tileBoard[y][x]; } + public int getHeight() { return this.height; } + public int getWidth() { return this.width; } + + public void setHeight(int newHeight) { this.height = newHeight; } + public void setWidth(int newWidth) { this.width = newWidth; } + public void setTile(int x, int y, TileType newTile) { + this.tileBoard[y][x] = newTile; + } + public void setTileBoard(TileType[][] newBoard) { + this.tileBoard = newBoard; + } + +} diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java b/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java new file mode 100644 index 0000000..ef33488 --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java @@ -0,0 +1,85 @@ +package com.gr15.pacman.model; + +import java.util.Map; + +import com.gr15.pacman.model.entities.Entity; +import com.gr15.pacman.model.entities.EntityUtils; +import com.gr15.pacman.model.entities.Items; +import com.gr15.pacman.model.entities.Pacman; + +/** + * GameState + */ +public class GameState { + + private Board board; + + private Pacman pacman; + private Map<Position, Entity> entities; + private Map<Position, Items> items; + + private int score = 0; + private int lives = 3; + private double powerModeDuration = 0; + + public GameState(Board board, Pacman pacman, + Map<Position, Entity> entities, Map<Position, Items> items) { + this.board = board; + this.entities = entities; + this.items = items; + this.pacman = pacman; + } + + public void update(double deltaSeconds) { + if (lives == 0) { + /* Gameover */ + } + + pacman.move(board, deltaSeconds); + + /* Power mode */ + powerModeDuration -= deltaSeconds; + powerModeDuration = Math.max(powerModeDuration, 0); + + /* updating and checking collisions with entities */ + entities.forEach((pos, entity) -> { + entity.move(board, deltaSeconds); + if (EntityUtils.hasCollided(pacman, entity) + && powerModeDuration == 0) { + lives -= 1; + } else if (EntityUtils.hasCollided(pacman, entity)) { + score += 100; + } + }); + + /* checking collisions with items */ + Items item = items.get(pacman.getPosition()); + if (item != null) { + switch (item) { + case PELLET -> score++; + case POWER_PELLET -> powerModeDuration = 10.0; + default -> {} + } + } + } + + /* Getters and setters */ + public Board getBoard() { return this.board; } + public Pacman getPacman() { return this.pacman; } + public Map<Position, Entity> getEntities() { return this.entities; } + public Map<Position, Items> getItems() { return this.items; } + public int getScore() { return this.score; } + public int getLives() { return this.lives; } + + public void setBoard(Board newBoard) { this.board = newBoard; } + public void setPacman(Pacman newPacman) { this.pacman = newPacman; } + public void setScore(int newScore) { this.score = newScore; } + public void setLives(int newLives) { this.lives = newLives; } + + public void setItems(Map<Position, Items> newItems) { + this.items = newItems; + } + public void setEntities(Map<Position, Entity> newEntities) { + this.entities = newEntities; + } +} 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 new file mode 100644 index 0000000..728fbd2 --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java @@ -0,0 +1,36 @@ +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.Board.TileType; +import com.gr15.pacman.model.entities.Entity; +import com.gr15.pacman.model.entities.Pacman; +import com.gr15.pacman.model.entities.Items; + +/** + * jsonParser + */ +public final class JsonParser { + + public static GameState getGameState(String path) { + TileType[][] tileBoard = { + {TileType.WALL, TileType.WALL, TileType.WALL, TileType.WALL, TileType.WALL,}, + {TileType.WALL, TileType.EMPTY, TileType.EMPTY, TileType.EMPTY, TileType.WALL,}, + {TileType.WALL, TileType.EMPTY, TileType.WALL, TileType.EMPTY, TileType.WALL,}, + {TileType.WALL, TileType.EMPTY, TileType.WALL, TileType.EMPTY, TileType.WALL,}, + {TileType.WALL, TileType.EMPTY, TileType.EMPTY, TileType.EMPTY, TileType.WALL,}, + {TileType.WALL, TileType.EMPTY, TileType.WALL, TileType.EMPTY, TileType.WALL,}, + {TileType.WALL, TileType.EMPTY, TileType.EMPTY, TileType.EMPTY, TileType.WALL,}, + {TileType.WALL, TileType.WALL, TileType.WALL, TileType.WALL, TileType.WALL,}, + }; + Board board = new Board(8, 5, tileBoard); + Pacman pacman = new Pacman(new Position(1, 1), 3.0, Direction.NONE, 1); + Map<Position, Entity> entities = new HashMap<>(); + Map<Position, Items> items = new HashMap<>(); + + return new GameState(board, pacman, entities, items); + } + +} 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 new file mode 100644 index 0000000..c492628 --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/Position.java @@ -0,0 +1,38 @@ +package com.gr15.pacman.model; + +import java.util.List; + +import com.gr15.pacman.model.Board.Direction; + +/** + * Position + */ +public record Position(int x, int y) { + + public Position offset(Direction dir) { + return switch(dir) { + case UP -> new Position(x, y-1); + case DOWN -> new Position(x, y+1); + case LEFT -> new Position(x-1, y); + case RIGHT -> new Position(x+1, y); + default -> this; + }; + } + + public double distance(Position other) { + return Math.hypot(other.x - x, other.y - y); + } + + public boolean inBounds(int width, int height) { + return x >= 0 && y >= 0 && x < width && y < height; + } + + public List<Position> neighbors() { + return List.of( + new Position(x, y+1), + new Position(x, y-1), + new Position(x-1, y), + new Position(x+1, y) + ); + } +} 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 new file mode 100644 index 0000000..395a170 --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Entity.java @@ -0,0 +1,36 @@ +package com.gr15.pacman.model.entities; + +import com.gr15.pacman.model.Board; +import com.gr15.pacman.model.Position; + +/** + * Entity + */ +public abstract class Entity { + + private Position position; + private float subTileX = 0.0f; + private float subTileY = 0.0f; + + private double radius; + + public Entity(Position startPos, double radius) { + this.radius = radius; + this.position = startPos; + } + + public abstract void move(Board board, double deltaSeconds); + + /* Getters and setters */ + public Position getPosition() { return this.position; } + public float getSubTileX() { return this.subTileX; } + public float getSubTileY() { return this.subTileY; } + public double getRadius() { return this.radius; } + public double getPositionX() { return position.x() + subTileX; } + public double getPositionY() { return position.y() + subTileY; } + + public void setPosition(Position newPos) { this.position = newPos; } + public void setSubTileX(float newX) { this.subTileX = newX; } + public void setSubTileY(float newY) { this.subTileY = newY; } + public void setRadius(double newRad) { this.radius = newRad; } +} diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/entities/EntityUtils.java b/pacman/model/src/main/java/com/gr15/pacman/model/entities/EntityUtils.java new file mode 100644 index 0000000..fd52acb --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/entities/EntityUtils.java @@ -0,0 +1,31 @@ +package com.gr15.pacman.model.entities; + +/** + * Util + */ +public final class EntityUtils { + + + public static double distance(Entity arg0, Entity arg1) { + double arg0X = arg0.getPosition().x() + arg0.getSubTileX(); + double arg0Y = arg0.getPosition().y() + arg0.getSubTileY(); + double arg1X = arg1.getPosition().x() + arg1.getSubTileX(); + double arg1Y = arg1.getPosition().y() + arg1.getSubTileY(); + + return Math.hypot(arg0X - arg1X, arg0Y - arg1Y); + } + + public static boolean hasCollided(Entity arg0, Entity arg1) { + double arg0X = arg0.getPosition().x() + arg0.getSubTileX(); + double arg0Y = arg0.getPosition().y() + arg0.getSubTileY(); + double arg1X = arg1.getPosition().x() + arg1.getSubTileX(); + double arg1Y = arg1.getPosition().y() + arg1.getSubTileY(); + + double dx = arg0X - arg1X; + double dy = arg0Y - arg1Y; + double distanceSquared = dx * dx + dy * dy; + double combinedRadius = arg0.getRadius() + arg1.getRadius(); + + return distanceSquared <= combinedRadius * combinedRadius; + } +} diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/entities/Ghost.java b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Ghost.java new file mode 100644 index 0000000..7ba795f --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Ghost.java @@ -0,0 +1,19 @@ +package com.gr15.pacman.model.entities; + +import com.gr15.pacman.model.Board; +import com.gr15.pacman.model.Position; + +/** + * Ghost + */ +public class Ghost + extends Entity{ + + public Ghost(Position startPos, double radius) { + super(startPos, radius); + } + @Override + public void move(Board board, double deltaSeconds) { + // TODO Auto-generated method stub + } +} diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/entities/Items.java b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Items.java new file mode 100644 index 0000000..3b09a54 --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Items.java @@ -0,0 +1,3 @@ +package com.gr15.pacman.model.entities; + +public enum Items { PELLET, POWER_PELLET }; 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 new file mode 100644 index 0000000..5d9cf22 --- /dev/null +++ b/pacman/model/src/main/java/com/gr15/pacman/model/entities/Pacman.java @@ -0,0 +1,145 @@ +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 + */ +public class Pacman + extends Entity { + + /* Tiles per second */ + private double speed; + private Direction currentDirection = Direction.NONE; + private Direction nextDirection; + + public Pacman(Position startPos, double speed, Direction startDir, double radius) { + super(startPos, radius); + this.speed = speed; + this.nextDirection = startDir; + } + + @Override + public void move(Board board, double deltaSeconds) { + float subTileX = super.getSubTileX(); + float subTileY = super.getSubTileY(); + 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); + + 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; + } + + boolean verticalMove = direction == Direction.UP + || direction == Direction.DOWN; + int directionSign = (direction == Direction.UP + || direction == Direction.LEFT) ? -1 : 1; + + /* 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); + + /* First, move to center if needed */ + if (distanceToCenter > 0.01) { + double moveToCenter = Math.min(distanceToMove, distanceToCenter); + if (subTileSecondary < center) { + subTileSecondary += moveToCenter; + } else { + subTileSecondary -= moveToCenter; + } + distanceToMove -= moveToCenter; + } + + /* Apply secondary axis back */ + if (verticalMove) { + subTileX = (float)subTileSecondary; + } else { + subTileY = (float)subTileSecondary; + } + + /* Now, attempt to move along primary axis */ + while (distanceToMove > 0.0001) { + double maxStep = directionSign > 0 ? 1.0 - subTilePrimary + : subTilePrimary; + double step = Math.min(distanceToMove, maxStep); + double newSubTilePrimary = subTilePrimary + 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; + } else { + currentDirection = Direction.NONE; + subTilePrimary = directionSign > 0 ? 1.0 : 0.0; + break; + } + } else { + subTilePrimary = newSubTilePrimary; + } + + distanceToMove -= step; + } + + /* Assign back primary axis */ + if (verticalMove) { + subTileY = (float)subTilePrimary; + } else { + subTileX = (float)subTilePrimary; + } + + /* Update direction state */ + if (canMoveNext) { + currentDirection = nextDirection; + nextDirection = Direction.NONE; + } + + /* Update final state */ + super.setSubTileX(subTileX); + super.setSubTileY(subTileY); + super.setPosition(currentPos); + } + + /* Getters and setters */ + public double getSpeed() { return this.speed; } + public Direction getDirection() { return this.currentDirection; } + public void setSpeed(double newSpeed) { this.speed = newSpeed; } + public void setDirection(Direction newDir) { this.nextDirection = newDir; } +} diff --git a/pacman/model/src/main/java/module-info.java b/pacman/model/src/main/java/module-info.java index b8cd128..95d9324 100644 --- a/pacman/model/src/main/java/module-info.java +++ b/pacman/model/src/main/java/module-info.java @@ -1,7 +1,8 @@ /* module-info.java * This acts as the manifest for the module. */ -module pacman.model { - requires javafx.controls; /* Declares a dependency on another module */ - exports pacman.model; /* exports make specific packages */ -} /* public to other modules */ +module com.gr15.pacman.model { + requires transitive javafx.controls; + exports com.gr15.pacman.model; + exports com.gr15.pacman.model.entities; +} diff --git a/pacman/model/src/main/resources/maps/testmap.json b/pacman/model/src/main/resources/maps/testmap.json new file mode 100644 index 0000000..547f48f --- /dev/null +++ b/pacman/model/src/main/resources/maps/testmap.json @@ -0,0 +1,20 @@ + +{ + "spooky": true, + "pacManSpawn": [ + { + "x": 1, + "y": 1 + } + ], + "tileBoard": [ + "x","x","x","x","x", + "x","e","e","e","x", + "x","e","x","e","x", + "x","e","e","e","x", + "x","x","e","x","x", + "x","e","e","e","x", + "x","x","e","x","x", + "x","x","x","x","x" + ] +} |