summaryrefslogtreecommitdiff
path: root/pacman
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--pacman/controller/pom.xml2
-rw-r--r--pacman/controller/src/main/java/com/gr15/pacman/controller/GameApp.java45
-rw-r--r--pacman/controller/src/main/java/com/gr15/pacman/controller/GameController.java65
-rw-r--r--pacman/controller/src/main/java/module-info.java10
-rw-r--r--pacman/controller/src/main/java/pacman/controller/GameApp.java21
-rw-r--r--pacman/model/pom.xml14
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/Board.java49
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/GameState.java85
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java36
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/Position.java38
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/entities/Entity.java36
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/entities/EntityUtils.java31
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/entities/Ghost.java19
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/entities/Items.java3
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/entities/Pacman.java145
-rw-r--r--pacman/model/src/main/java/module-info.java9
-rw-r--r--pacman/model/src/main/resources/maps/testmap.json20
-rw-r--r--pacman/pom.xml4
-rw-r--r--pacman/view/src/main/java/com/gr15/pacman/view/AnimatedSprite.java31
-rw-r--r--pacman/view/src/main/java/com/gr15/pacman/view/GameView.java109
-rw-r--r--pacman/view/src/main/java/com/gr15/pacman/view/Sprite.java35
-rw-r--r--pacman/view/src/main/java/module-info.java11
-rw-r--r--pacman/view/src/main/resources/gameAssets/blueGhost.pngbin0 -> 258 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/cherry.pngbin0 -> 271 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/cherry2.pngbin0 -> 223 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/orangeGhost.pngbin0 -> 246 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/pacmanDown.pngbin0 -> 204 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/pacmanLeft.pngbin0 -> 203 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/pacmanRight.pngbin0 -> 205 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/pacmanUp.pngbin0 -> 207 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/pinkGhost.pngbin0 -> 249 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/redGhost.pngbin0 -> 249 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/scaredGhost.pngbin0 -> 239 bytes
-rw-r--r--pacman/view/src/main/resources/gameAssets/wall.pngbin0 -> 152 bytes
34 files changed, 778 insertions, 40 deletions
diff --git a/pacman/controller/pom.xml b/pacman/controller/pom.xml
index e3a99f8..6baf25f 100644
--- a/pacman/controller/pom.xml
+++ b/pacman/controller/pom.xml
@@ -34,7 +34,7 @@
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
- <mainClass>pacman.controller.GameApp</mainClass>
+ <mainClass>com.gr15.pacman.controller.GameApp</mainClass>
</configuration>
</plugin>
</plugins>
diff --git a/pacman/controller/src/main/java/com/gr15/pacman/controller/GameApp.java b/pacman/controller/src/main/java/com/gr15/pacman/controller/GameApp.java
new file mode 100644
index 0000000..1c8bc75
--- /dev/null
+++ b/pacman/controller/src/main/java/com/gr15/pacman/controller/GameApp.java
@@ -0,0 +1,45 @@
+package com.gr15.pacman.controller;
+
+import com.gr15.pacman.model.GameState;
+import com.gr15.pacman.model.JsonParser;
+import com.gr15.pacman.view.GameView;
+
+import javafx.application.Application;
+import javafx.stage.Stage;
+
+/**
+ * GameApp
+ */
+public class GameApp
+ extends Application {
+
+ GameController gameController;
+ GameView gameView;
+ GameState gameState;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ primaryStage.setTitle("Pac-Man");
+ primaryStage.setResizable(false);
+ primaryStage.setFullScreen(true);
+
+ try {
+ gameState = JsonParser.getGameState("test");
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to load game state: " + e.getMessage());
+ }
+
+ gameView = new GameView(gameState, 8, 5);
+ primaryStage.setScene(gameView);
+
+ gameController = new GameController(gameState, gameView);
+ gameController.startGameLoop();
+
+ primaryStage.show();
+ }
+
+ public static void main(String[] args) {
+ launch(args);
+ }
+}
diff --git a/pacman/controller/src/main/java/com/gr15/pacman/controller/GameController.java b/pacman/controller/src/main/java/com/gr15/pacman/controller/GameController.java
new file mode 100644
index 0000000..b1208be
--- /dev/null
+++ b/pacman/controller/src/main/java/com/gr15/pacman/controller/GameController.java
@@ -0,0 +1,65 @@
+package com.gr15.pacman.controller;
+
+import com.gr15.pacman.model.GameState;
+import com.gr15.pacman.model.Board.Direction;
+import com.gr15.pacman.view.GameView;
+
+import javafx.animation.AnimationTimer;
+import javafx.scene.paint.Color;
+
+/**
+ * GameController
+ */
+public class GameController {
+
+ private GameState gameState;
+ private GameView gameView;
+
+ private AnimationTimer gameLoop;
+ private long lastUpdate = 0;
+
+ public GameController(GameState gameState, GameView gameView) {
+ this.gameState = gameState;
+ this.gameView = gameView;
+ gameView.setFill(Color.BLACK);
+
+ setupEventHandlers();
+ gameLoop = new AnimationTimer() {
+
+ @Override
+ public void handle(long now) {
+ if (lastUpdate == 0) {
+ lastUpdate = now;
+ return; /* returning early, since no time have elapsed */
+ }
+
+ double deltaSeconds = (now - lastUpdate) / 1_000_000_000.0;
+ lastUpdate = now;
+
+ gameState.update(deltaSeconds);
+ gameView.renderGame(deltaSeconds);
+ }
+ };
+ }
+
+ private void setupEventHandlers() {
+ gameView.setOnKeyPressed(event -> {
+ switch (event.getCode()) {
+ case UP -> gameState.getPacman().setDirection(Direction.UP);
+ case DOWN -> gameState.getPacman().setDirection(Direction.DOWN);
+ case LEFT -> gameState.getPacman().setDirection(Direction.LEFT);
+ case RIGHT -> gameState.getPacman().setDirection(Direction.RIGHT);
+ default -> {}
+ }
+ });
+ }
+
+ public void startGameLoop() {
+ gameLoop.start();
+ }
+
+ public void stopGameLoop() {
+ lastUpdate = 0;
+ gameLoop.stop();
+ }
+}
diff --git a/pacman/controller/src/main/java/module-info.java b/pacman/controller/src/main/java/module-info.java
index 75c422d..8b4e271 100644
--- a/pacman/controller/src/main/java/module-info.java
+++ b/pacman/controller/src/main/java/module-info.java
@@ -1,9 +1,7 @@
/* module-info.java
* This acts as the manifest for the module.
*/
-module pacman.controller {
- requires javafx.controls; /* Declares a dependency on another module */
- requires pacman.model; /* Should depenend on model, */
- requires pacman.view; /* and view */
- exports pacman.controller; /* exports make specific packages */
-} /* public to other modules */
+module com.gr15.pacman.controller {
+ requires transitive com.gr15.pacman.view;
+ exports com.gr15.pacman.controller;
+}
diff --git a/pacman/controller/src/main/java/pacman/controller/GameApp.java b/pacman/controller/src/main/java/pacman/controller/GameApp.java
deleted file mode 100644
index 648dc15..0000000
--- a/pacman/controller/src/main/java/pacman/controller/GameApp.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package pacman.controller;
-
-import javafx.application.Application;
-import javafx.stage.Stage;
-
-/**
- * GameApp
- */
-public class GameApp
- extends Application {
-
- @Override
- public void start(Stage arg0) throws Exception {
- // TODO Auto-generated method stub
-
- }
-
- public static void main(String[] args) {
- launch(args);
- }
-}
diff --git a/pacman/model/pom.xml b/pacman/model/pom.xml
new file mode 100644
index 0000000..02e5fb8
--- /dev/null
+++ b/pacman/model/pom.xml
@@ -0,0 +1,14 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://www.w3.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.gr15</groupId>
+ <artifactId>pacman</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>model</artifactId>
+</project>
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"
+ ]
+}
diff --git a/pacman/pom.xml b/pacman/pom.xml
index f083890..9299cd5 100644
--- a/pacman/pom.xml
+++ b/pacman/pom.xml
@@ -11,8 +11,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <maven.compiler.source>17</maven.compiler.source>
- <maven.compiler.target>17</maven.compiler.target>
+ <maven.compiler.source>24</maven.compiler.source>
+ <maven.compiler.target>24</maven.compiler.target>
<javafx.version>17.0.2</javafx.version> <!-- Centralized JavaFX version -->
</properties>
diff --git a/pacman/view/src/main/java/com/gr15/pacman/view/AnimatedSprite.java b/pacman/view/src/main/java/com/gr15/pacman/view/AnimatedSprite.java
new file mode 100644
index 0000000..763c876
--- /dev/null
+++ b/pacman/view/src/main/java/com/gr15/pacman/view/AnimatedSprite.java
@@ -0,0 +1,31 @@
+package com.gr15.pacman.view;
+
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.image.Image;
+
+public class AnimatedSprite extends Sprite {
+ private Image[] frames;
+ private int currentFrame = 0;
+ private double frameTime = 0.1; // seconds per frame
+ private double timeSinceLastFrame = 0.0;
+
+ public AnimatedSprite(Image[] frames, double x, double y, double width, double height) {
+ super(frames[0], x, y, width, height);
+ this.frames = frames;
+ }
+
+ public void update(double deltaSeconds) {
+ timeSinceLastFrame += deltaSeconds;
+ if (timeSinceLastFrame >= frameTime) {
+ currentFrame = (currentFrame + 1) % frames.length;
+ super.setImage(frames[currentFrame]);
+ timeSinceLastFrame = 0.0;
+ }
+ }
+
+ @Override
+ public void render(GraphicsContext gc) {
+ super.render(gc);
+ }
+}
+
diff --git a/pacman/view/src/main/java/com/gr15/pacman/view/GameView.java b/pacman/view/src/main/java/com/gr15/pacman/view/GameView.java
new file mode 100644
index 0000000..62617d6
--- /dev/null
+++ b/pacman/view/src/main/java/com/gr15/pacman/view/GameView.java
@@ -0,0 +1,109 @@
+package com.gr15.pacman.view;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.gr15.pacman.model.GameState;
+import com.gr15.pacman.model.Board.TileType;
+
+import javafx.scene.Scene;
+import javafx.scene.canvas.Canvas;
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.image.Image;
+import javafx.scene.layout.StackPane;
+
+import com.gr15.pacman.model.entities.Entity;
+import com.gr15.pacman.model.entities.Items;
+
+/**
+ * GameView
+ */
+public class GameView
+ extends Scene {
+
+ /* Utils */
+ private Canvas canvas;
+ private GraphicsContext gc;
+ private GameState gameState;
+ private StackPane root;
+
+ private float scaleX = 4.0f;
+ private float scaleY = 4.0f;
+ private int tileHeight;
+ private int tileWidth;
+
+ private Map<TileType, Image> tileTextures = new HashMap<>();
+ private Map<Entity, Image> entityTextures = new HashMap<>();
+ private Map<Items, Image> itemTextures = new HashMap<>();
+
+ /* UI elements */
+ private Sprite pacmanSprite;
+
+ public GameView(GameState gameState,
+ int tileHeight, int tileWidth) {
+ super(new StackPane());
+ root = (StackPane)super.getRoot();
+
+ canvas = new Canvas(tileWidth * 16 * scaleX, tileHeight * 16 * scaleY);
+ gc = canvas.getGraphicsContext2D();
+ root.getChildren().add(canvas);
+
+ this.tileHeight = tileHeight;
+ this.tileWidth = tileWidth;
+ this.gameState = gameState;
+
+ tileTextures.put(TileType.WALL, new Image(
+ this.getClass().getResourceAsStream("/gameAssets/wall.png")));
+ pacmanSprite = new Sprite(new Image(
+ this.getClass().getResourceAsStream("/gameAssets/pacmanRight.png")),
+ gameState.getPacman().getPositionX() - 0.5,
+ gameState.getPacman().getPositionY() - 0.5,
+ 16 * scaleX, 16 * scaleY);
+ }
+
+ public void renderGame(double deltaSeconds) {
+ gc.clearRect(0, 0, tileWidth * 16 * scaleX, tileHeight * 16 * scaleY);
+ TileType[][] tileBoard = gameState.getBoard().getTileBoard();
+ for (int y = 0; y < tileBoard.length; y++) {
+ for (int x = 0; x < tileBoard[y].length; x++) {
+ Image texture = tileTextures.get(tileBoard[y][x]);
+ if (texture != null) {
+ gc.drawImage(texture,
+ x * 16 * scaleX,
+ y * 16 * scaleY,
+ texture.getWidth() * scaleX,
+ texture.getHeight() * scaleY);
+ }
+ }
+ }
+
+ pacmanSprite.setX((gameState.getPacman().getPositionX()
+ - 0.5) * 16 * scaleX);
+ pacmanSprite.setY((gameState.getPacman().getPositionY()
+ - 0.5) * 16 * scaleY);
+ pacmanSprite.render(gc);
+
+ gameState.getEntities().forEach((pos, entity) -> {
+ Image texture = entityTextures.get(entity);
+ if (texture != null) {
+ gc.drawImage(texture,
+ entity.getPositionX() * 16 * scaleX,
+ entity.getPositionY() * 16 * scaleY,
+ texture.getWidth() * scaleX,
+ texture.getHeight() * scaleY);
+ }
+ });
+
+ gameState.getItems().forEach((pos, item) -> {
+ Image texture = itemTextures.get(item);
+ if (texture != null) {
+ gc.drawImage(texture,
+ pos.x() * 16 * scaleX,
+ pos.y() * 16 * scaleY,
+ texture.getWidth() * scaleX,
+ texture.getHeight() * scaleY);
+
+ }
+ });
+ }
+}
diff --git a/pacman/view/src/main/java/com/gr15/pacman/view/Sprite.java b/pacman/view/src/main/java/com/gr15/pacman/view/Sprite.java
new file mode 100644
index 0000000..f397e7d
--- /dev/null
+++ b/pacman/view/src/main/java/com/gr15/pacman/view/Sprite.java
@@ -0,0 +1,35 @@
+package com.gr15.pacman.view;
+
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.image.Image;
+
+public class Sprite {
+ private Image image;
+ private double x, y;
+ private double width, height;
+
+ public Sprite(Image image, double x, double y, double width, double height) {
+ this.image = image;
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ public void render(GraphicsContext gc) {
+ gc.drawImage(image, x, y, width, height);
+ }
+
+ /* Getters and setters */
+ public Image getImage() { return this.image; }
+ public double getX() { return this.x; }
+ public double getY() { return this.y; }
+ public double getWidth() { return this.width; }
+ public double getHeigt() { return this.height; }
+
+ public void setImage(Image newImage) { this.image = newImage; }
+ public void setX(double newX) { this.x = newX; }
+ public void setY(double newY) { this.y = newY; }
+ public void setWidth(double newWidth) { this.width = newWidth; }
+ public void setHeight(double newHeight) { this.height = newHeight; }
+}
diff --git a/pacman/view/src/main/java/module-info.java b/pacman/view/src/main/java/module-info.java
index a9649df..914038a 100644
--- a/pacman/view/src/main/java/module-info.java
+++ b/pacman/view/src/main/java/module-info.java
@@ -1,9 +1,8 @@
/* module-info.java
* This acts as the manifest for the module.
*/
-module pacman.view {
- requires javafx.controls; /* JavaFX dependencies */
- requires javafx.graphics;
- requires pacman.model;
- exports pacman.view; /* exports make specific packages */
-} /* public to other modules */
+module com.gr15.pacman.view {
+ requires transitive javafx.graphics;
+ requires transitive com.gr15.pacman.model;
+ exports com.gr15.pacman.view;
+}
diff --git a/pacman/view/src/main/resources/gameAssets/blueGhost.png b/pacman/view/src/main/resources/gameAssets/blueGhost.png
new file mode 100644
index 0000000..e1ee979
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/blueGhost.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/cherry.png b/pacman/view/src/main/resources/gameAssets/cherry.png
new file mode 100644
index 0000000..45c4f31
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/cherry.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/cherry2.png b/pacman/view/src/main/resources/gameAssets/cherry2.png
new file mode 100644
index 0000000..6dea0ca
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/cherry2.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/orangeGhost.png b/pacman/view/src/main/resources/gameAssets/orangeGhost.png
new file mode 100644
index 0000000..bcd1cb8
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/orangeGhost.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/pacmanDown.png b/pacman/view/src/main/resources/gameAssets/pacmanDown.png
new file mode 100644
index 0000000..2c24dbe
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/pacmanDown.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/pacmanLeft.png b/pacman/view/src/main/resources/gameAssets/pacmanLeft.png
new file mode 100644
index 0000000..168f495
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/pacmanLeft.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/pacmanRight.png b/pacman/view/src/main/resources/gameAssets/pacmanRight.png
new file mode 100644
index 0000000..7e370a0
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/pacmanRight.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/pacmanUp.png b/pacman/view/src/main/resources/gameAssets/pacmanUp.png
new file mode 100644
index 0000000..9f4a39b
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/pacmanUp.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/pinkGhost.png b/pacman/view/src/main/resources/gameAssets/pinkGhost.png
new file mode 100644
index 0000000..12c3f84
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/pinkGhost.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/redGhost.png b/pacman/view/src/main/resources/gameAssets/redGhost.png
new file mode 100644
index 0000000..cfd374e
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/redGhost.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/scaredGhost.png b/pacman/view/src/main/resources/gameAssets/scaredGhost.png
new file mode 100644
index 0000000..9e26fff
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/scaredGhost.png
Binary files differ
diff --git a/pacman/view/src/main/resources/gameAssets/wall.png b/pacman/view/src/main/resources/gameAssets/wall.png
new file mode 100644
index 0000000..ab12c87
--- /dev/null
+++ b/pacman/view/src/main/resources/gameAssets/wall.png
Binary files differ