summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormithe24 <mithe24@student.sdu.dk>2025-05-07 17:11:58 +0200
committerGitHub <noreply@github.com>2025-05-07 17:11:58 +0200
commitc164daed53574babb26796b05682432709e2c5c1 (patch)
tree50690b34f82847368be7c08c54b4489d4fea3e15
parentec0f4221ecd71c0b18e8403daa58b66077ec4343 (diff)
downloadpacman-c164daed53574babb26796b05682432709e2c5c1.tar.gz
pacman-c164daed53574babb26796b05682432709e2c5c1.zip
Feature/json parser (#18)
* chore(model/json-parser): Added maven dependency * chore(model): Removed old test JSON file * refactor(model/GameState): List better then map, entities should be able to overlap * feat(Pacman): Added GameState builder to initiate GameState with given paramters. Added a short example JSON-file, more key-value pairs needs to be added as the game progresses. Likewise the builder won't parse for any other key-value pair automatically.
Diffstat (limited to '')
-rw-r--r--pacman/controller/src/main/java/com/gr15/pacman/controller/GameApp.java19
-rw-r--r--pacman/controller/src/main/resources/testGameState.json22
-rw-r--r--pacman/model/pom.xml8
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/GameState.java15
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/GameStateBuilder.java117
-rw-r--r--pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java36
-rw-r--r--pacman/model/src/main/java/module-info.java1
-rw-r--r--pacman/model/src/main/resources/maps/testmap.json20
-rw-r--r--pacman/view/src/main/java/com/gr15/pacman/view/GameView.java6
9 files changed, 170 insertions, 74 deletions
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
index 1c8bc75..ffd4493 100644
--- a/pacman/controller/src/main/java/com/gr15/pacman/controller/GameApp.java
+++ b/pacman/controller/src/main/java/com/gr15/pacman/controller/GameApp.java
@@ -1,7 +1,9 @@
package com.gr15.pacman.controller;
+import java.io.InputStream;
+
import com.gr15.pacman.model.GameState;
-import com.gr15.pacman.model.JsonParser;
+import com.gr15.pacman.model.GameStateBuilder;
import com.gr15.pacman.view.GameView;
import javafx.application.Application;
@@ -23,14 +25,13 @@ public class GameApp
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);
+ InputStream inputStream = this.getClass()
+ .getResourceAsStream("/testGameState.json");
+ GameState gameState = GameStateBuilder.fromJson(inputStream);
+ inputStream.close();
+ int tileWidth = gameState.getBoard().getWidth();
+ int tileHeight = gameState.getBoard().getHeight();
+ gameView = new GameView(gameState,tileWidth, tileHeight);
primaryStage.setScene(gameView);
gameController = new GameController(gameState, gameView);
diff --git a/pacman/controller/src/main/resources/testGameState.json b/pacman/controller/src/main/resources/testGameState.json
new file mode 100644
index 0000000..48e333a
--- /dev/null
+++ b/pacman/controller/src/main/resources/testGameState.json
@@ -0,0 +1,22 @@
+{
+ "pacman": {
+ "x": 1,
+ "y": 1,
+ "speed": 3.0,
+ "radius": 1.0
+ },
+
+ "itmes": [],
+ "board": [
+ ["W","W","W","W","W","W","W","W","W"],
+ ["W","E","E","E","E","E","E","E","W"],
+ ["E","E","W","W","E","W","W","E","E"],
+ ["W","E","W","W","E","W","W","E","W"],
+ ["W","E","W","W","E","W","W","E","W"],
+ ["W","E","E","E","E","E","E","E","W"],
+ ["W","E","W","W","E","W","W","E","W"],
+ ["E","E","W","W","E","W","W","E","E"],
+ ["W","E","E","E","E","E","E","E","W"],
+ ["W","W","W","W","W","W","W","W","W"]
+ ]
+}
diff --git a/pacman/model/pom.xml b/pacman/model/pom.xml
index 02e5fb8..6eac4b2 100644
--- a/pacman/model/pom.xml
+++ b/pacman/model/pom.xml
@@ -11,4 +11,12 @@
</parent>
<artifactId>model</artifactId>
+ <dependencies>
+ <!-- https://mvnrepository.com/artifact/org.json/json -->
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20250107</version>
+ </dependency>
+ </dependencies>
</project>
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
index ef33488..609bfc0 100644
--- a/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java
+++ b/pacman/model/src/main/java/com/gr15/pacman/model/GameState.java
@@ -1,5 +1,6 @@
package com.gr15.pacman.model;
+import java.util.List;
import java.util.Map;
import com.gr15.pacman.model.entities.Entity;
@@ -15,15 +16,15 @@ public class GameState {
private Board board;
private Pacman pacman;
- private Map<Position, Entity> entities;
+ private List<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) {
+ protected GameState(Board board, Pacman pacman,
+ List<Entity> entities, Map<Position, Items> items) {
this.board = board;
this.entities = entities;
this.items = items;
@@ -42,7 +43,7 @@ public class GameState {
powerModeDuration = Math.max(powerModeDuration, 0);
/* updating and checking collisions with entities */
- entities.forEach((pos, entity) -> {
+ for (Entity entity : entities) {
entity.move(board, deltaSeconds);
if (EntityUtils.hasCollided(pacman, entity)
&& powerModeDuration == 0) {
@@ -50,7 +51,7 @@ public class GameState {
} else if (EntityUtils.hasCollided(pacman, entity)) {
score += 100;
}
- });
+ }
/* checking collisions with items */
Items item = items.get(pacman.getPosition());
@@ -66,7 +67,7 @@ public class GameState {
/* Getters and setters */
public Board getBoard() { return this.board; }
public Pacman getPacman() { return this.pacman; }
- public Map<Position, Entity> getEntities() { return this.entities; }
+ public List<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; }
@@ -79,7 +80,7 @@ public class GameState {
public void setItems(Map<Position, Items> newItems) {
this.items = newItems;
}
- public void setEntities(Map<Position, Entity> newEntities) {
+ public void setEntities(List<Entity> newEntities) {
this.entities = newEntities;
}
}
diff --git a/pacman/model/src/main/java/com/gr15/pacman/model/GameStateBuilder.java b/pacman/model/src/main/java/com/gr15/pacman/model/GameStateBuilder.java
new file mode 100644
index 0000000..aab7dd9
--- /dev/null
+++ b/pacman/model/src/main/java/com/gr15/pacman/model/GameStateBuilder.java
@@ -0,0 +1,117 @@
+package com.gr15.pacman.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+
+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.Ghost;
+import com.gr15.pacman.model.entities.Items;
+import com.gr15.pacman.model.entities.Pacman;
+
+/**
+ * Utility class to build a {@link GameState} object from a JSON configuration.
+ *
+ * <p>
+ * This class provides static methods to parse game data such as the board,
+ * entities, and items from a JSON input stream and use it to initialize
+ * a game state. It handles parsing logic and translates string representations
+ * into model objects used by the game engine.
+ * </p>
+ */
+public class GameStateBuilder {
+
+ /**
+ Parses a JSON input stream and constructs a {@link GameState} based on the configuration.
+ * <p>
+ * Expected JSON structure includes:
+ * <ul>
+ * <li>{@code pacmanSpawnPoint}: an array of two integers
+ * representing the X and Y coordinates.</li>
+ * <li>{@code board}: a 2D array of strings
+ * representing the board tiles ("W" for wall, "E" for empty).</li>
+ * <li>{@code pacman}: a JSON object containing properties
+ * such as {@code x}, {@code y}, {@code speed}, and {@code radius}.</li>
+ * </ul>
+ *
+ * @param inputStream the input stream of the JSON file.
+ * @return a {@link GameState} object built from the JSON configuration.
+ * @throws RuntimeException if the JSON is invalid or the file cannot be read.
+ */
+ public static GameState fromJson(InputStream inputStream) {
+ /* Reader gets closed automatically,
+ * because it's in the resources part of a try-with-resource statement.
+ * The InputStream gets closed by Reader */
+ try (InputStreamReader reader = new InputStreamReader(inputStream)) {
+ JSONTokener tokener = new JSONTokener(reader);
+ JSONObject jsonObject = new JSONObject(tokener);
+ return buildFromJsonObject(jsonObject);
+ } catch (JSONException jsonException) {
+ throw new RuntimeException("""
+ Failed to parse JSON content.
+ Please ensure the file contains valid JSON.""", jsonException);
+ } catch (IOException ioException) {
+ throw new RuntimeException("""
+ Error reading JSON file.
+ Ensure the file exists and is accessible""", ioException);
+ }
+ }
+
+ /**
+ * Internal helper method that constructs a {@link GameState} object
+ * from a given {@link JSONObject}.
+ *
+ * <p>
+ * This method extracts the board layout, Pacman parameters,
+ * and initializes the entities and items.
+ *
+ * @param jsonObject the JSON object containing game configuration data.
+ * @return a fully constructed {@link GameState} object.
+ * @throws RuntimeException if required fields are missing or incorrectly formatted.
+
+ */
+ private static GameState buildFromJsonObject(JSONObject jsonObject) {
+ try {
+ JSONArray stringBoard = jsonObject.getJSONArray("board");
+ TileType[][] tileBoard = new TileType
+ [stringBoard.length()]
+ [stringBoard.getJSONArray(0).length()];
+ for (int y = 0; y < stringBoard.length(); y++) {
+ JSONArray row = stringBoard.getJSONArray(y);
+ for (int x = 0; x < row.length(); x++) {
+ switch (row.getString(x)) {
+ case "W" -> tileBoard[y][x] = TileType.WALL;
+ case "E" -> tileBoard[y][x] = TileType.EMPTY;
+ default -> {}
+ }
+ }
+ }
+ Board board = new Board(tileBoard[0].length, tileBoard.length, tileBoard);
+
+ JSONObject pacmanJsonObject = jsonObject.getJSONObject("pacman");
+ double speed = pacmanJsonObject.getDouble("speed");
+ double radius = pacmanJsonObject.getDouble("radius");
+ Position pacmanStartPos = new Position(
+ pacmanJsonObject.getInt("x"),
+ pacmanJsonObject.getInt("y"));
+ Pacman pacman = new Pacman(pacmanStartPos, speed, Direction.NONE, radius);
+
+ ArrayList<Entity> entities = new ArrayList<>();
+ Map<Position, Items> items = new HashMap<>();
+
+ return new GameState(board, pacman, entities, items);
+ } catch (JSONException jsonException) {
+ throw new RuntimeException("Failed to parse GameState json", jsonException);
+ }
+ }
+}
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
deleted file mode 100644
index 990fb15..0000000
--- a/pacman/model/src/main/java/com/gr15/pacman/model/JsonParser.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.gr15.pacman.model;
-
-import java.util.HashMap;
-import java.util.Map;
-
-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;
-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/module-info.java b/pacman/model/src/main/java/module-info.java
index 95d9324..5a7d26d 100644
--- a/pacman/model/src/main/java/module-info.java
+++ b/pacman/model/src/main/java/module-info.java
@@ -3,6 +3,7 @@
*/
module com.gr15.pacman.model {
requires transitive javafx.controls;
+ requires org.json;
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
deleted file mode 100644
index 547f48f..0000000
--- a/pacman/model/src/main/resources/maps/testmap.json
+++ /dev/null
@@ -1,20 +0,0 @@
-
-{
- "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/view/src/main/java/com/gr15/pacman/view/GameView.java b/pacman/view/src/main/java/com/gr15/pacman/view/GameView.java
index 62617d6..d56a1e1 100644
--- a/pacman/view/src/main/java/com/gr15/pacman/view/GameView.java
+++ b/pacman/view/src/main/java/com/gr15/pacman/view/GameView.java
@@ -1,6 +1,7 @@
package com.gr15.pacman.view;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import com.gr15.pacman.model.GameState;
@@ -83,7 +84,8 @@ public class GameView
- 0.5) * 16 * scaleY);
pacmanSprite.render(gc);
- gameState.getEntities().forEach((pos, entity) -> {
+ List<Entity> entities = gameState.getEntities();
+ for (Entity entity : entities) {
Image texture = entityTextures.get(entity);
if (texture != null) {
gc.drawImage(texture,
@@ -92,7 +94,7 @@ public class GameView
texture.getWidth() * scaleX,
texture.getHeight() * scaleY);
}
- });
+ }
gameState.getItems().forEach((pos, item) -> {
Image texture = itemTextures.get(item);