From dc9dad4d9cfd2e04def0087cd516452176f560cc Mon Sep 17 00:00:00 2001 From: Urban Modig Date: Thu, 21 Aug 2025 13:50:22 +0200 Subject: [PATCH] Fixing minor improvements --- .../java/se/urmo/game/entities/Ghost.java | 15 +- .../game/entities/ScatterToBottomRight.java | 4 +- src/main/java/se/urmo/game/map/GameMap.java | 154 +++++++++++------- 3 files changed, 105 insertions(+), 68 deletions(-) diff --git a/src/main/java/se/urmo/game/entities/Ghost.java b/src/main/java/se/urmo/game/entities/Ghost.java index d795cce..35df042 100644 --- a/src/main/java/se/urmo/game/entities/Ghost.java +++ b/src/main/java/se/urmo/game/entities/Ghost.java @@ -19,7 +19,6 @@ import java.util.stream.Collectors; @Slf4j public class Ghost { private static final int COLLISION_BOX_SIZE = 16; - private static final int GHOST_SPEED = 1; private static final int GHOST_MOVEMENT_UPDATE_FREQUENCY = 2; public static final int GHOST_SIZE = 32; private static final int ANIMATION_UPDATE_FREQUENCY = 25; @@ -49,8 +48,8 @@ public class Ghost { this.scaterStrategy = scaterStrategy; this.animation = animation; position = new Point( - 13 * GameMap.MAP_TILESIZE + (GameMap.MAP_TILESIZE / 2) + GameMap.OFFSET_X, - 4 * GameMap.MAP_TILESIZE + (GameMap.MAP_TILESIZE / 2) + GameMap.OFFSET_Y); + 13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_X + (GameMap.MAP_TILESIZE / 2), + 4 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + (GameMap.MAP_TILESIZE / 2) ); this.currentStrategy = chaseStrategy; } @@ -86,8 +85,8 @@ public class Ghost { } Point newPosition = new Point( - position.x + direction.dx * GHOST_SPEED, - position.y + direction.dy * GHOST_SPEED); + position.x + direction.dx, + position.y + direction.dy); log.debug("Next position {}", newPosition); Point destination = collisionChecker.canMoveTo(direction, newPosition); @@ -124,15 +123,15 @@ public class Ghost { .orElse(Integer.MAX_VALUE); // Return all directions that have this priority - List l = options.entrySet().stream() + List directions = options.entrySet().stream() .filter(entry -> entry.getValue() == lowestPriority) .map(Map.Entry::getKey) .toList(); - Direction best = l.getFirst(); + Direction best = directions.getFirst(); double bestDist = Double.MAX_VALUE; - for (Direction d : l) { + for (Direction d : directions) { int nx = position.x + d.dx * GameMap.MAP_TILESIZE; int ny = position.y + d.dy * GameMap.MAP_TILESIZE; double dist = target.distance(nx, ny); diff --git a/src/main/java/se/urmo/game/entities/ScatterToBottomRight.java b/src/main/java/se/urmo/game/entities/ScatterToBottomRight.java index d1abdd5..40810e0 100644 --- a/src/main/java/se/urmo/game/entities/ScatterToBottomRight.java +++ b/src/main/java/se/urmo/game/entities/ScatterToBottomRight.java @@ -7,6 +7,8 @@ import java.awt.Point; public class ScatterToBottomRight implements GhostStrategy { @Override public Point chooseTarget(Ghost ghost, PacMan pacman, GameMap map) { - return new Point(map.getHeight() - 1, map.getHeight() - 1); + return new Point( + map.rowToWorldY(map.rows() - 1), + map.colToWorldX(map.columns() - 1)); } } diff --git a/src/main/java/se/urmo/game/map/GameMap.java b/src/main/java/se/urmo/game/map/GameMap.java index a0f24ae..070b8b7 100644 --- a/src/main/java/se/urmo/game/map/GameMap.java +++ b/src/main/java/se/urmo/game/map/GameMap.java @@ -1,53 +1,65 @@ package se.urmo.game.map; import lombok.extern.slf4j.Slf4j; -import se.urmo.game.main.GamePanel; import se.urmo.game.util.LoadSave; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; -import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.stream.IntStream; @Slf4j public class GameMap { public static final int MAP_TILESIZE = 16;// 16px from left + public static final int MAP_COL_SIZE = 28; + public static final int MAP_ROW_SIZE = 30; public static final int OFFSET_Y = 7 * MAP_TILESIZE; // 160px from top public static final int OFFSET_X = MAP_TILESIZE; // 16px from left private final BufferedImage[][] images = new BufferedImage[13][19]; - private MapTile[][] mapData; + private final MapTile[][] mapData; public GameMap() { loadSprites(); - loadMap("maps/map1.csv"); + mapData = loadMap("maps/map1.csv"); } - private void loadMap(String path) { - List rows = new ArrayList<>(); + private MapTile[][] loadMap(String path) { + MapTile[][] data = new MapTile[MAP_ROW_SIZE][MAP_COL_SIZE]; + try (InputStream is = getClass().getClassLoader().getResourceAsStream(path); BufferedReader br = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) { String line; - while ((line = br.readLine()) != null) { + int rowIndex = 0; + while ((line = br.readLine()) != null && rowIndex < MAP_ROW_SIZE) { String[] tokens = line.split(","); - int[] row = new int[tokens.length]; - for (int i = 0; i < tokens.length; i++) { - row[i] = Integer.parseInt(tokens[i].trim()); + if (tokens.length != MAP_COL_SIZE) { + throw new IllegalStateException( + "Invalid map format: row " + rowIndex + " has " + tokens.length + + " columns, expected " + MAP_COL_SIZE + ); } - rows.add(row); + + for (int col = 0; col < MAP_COL_SIZE; col++) { + int value = Integer.parseInt(tokens[col].trim()); + data[rowIndex][col] = new MapTile(getSprite(value), value); + } + rowIndex++; } - } catch (IOException | NullPointerException e) { - e.printStackTrace(); + if (rowIndex != MAP_ROW_SIZE) { + throw new IllegalStateException( + "Invalid map format: found " + rowIndex + " rows, expected " + MAP_ROW_SIZE + ); + } + + } catch (NullPointerException e) { + log.error("Failed to open inputstream: {}", e.getMessage(), e); + } catch (IOException e){ + log.error("Failed to read resource: {}", e.getMessage(), e); } - mapData = rows.stream() - .map(row -> IntStream.of(row) - .mapToObj(value -> new MapTile(getSprite(value), value)) - .toArray(MapTile[]::new)) - .toArray(MapTile[][]::new); + return data; } private BufferedImage getSprite(int value) { @@ -139,12 +151,13 @@ public class GameMap { public boolean isPassable(List list){ return list.stream().allMatch(p -> isPassable(p.x, p.y)); } - public boolean isPassable(int x, int y) { - int row = getRow(y); - int col = getCol(x); - int tileY = (y - OFFSET_Y) % MAP_TILESIZE; - int tileX = (x - OFFSET_X) % MAP_TILESIZE; - log.trace("Point[x="+x+",y="+y+"] is row="+ row + ", col=" + col + " with reminder x=" +tileX+",y=" +tileY); + + public boolean isPassable(int screenX, int screenY) { + int row = screenToRow(screenY); + int col = screenToCol(screenX); + int tileY = (screenY - OFFSET_Y) % MAP_TILESIZE; + int tileX = (screenX - OFFSET_X) % MAP_TILESIZE; + log.trace("Point[x={},y={}] is row={}, col={} with reminder x={},y={}", screenX, screenY, row, col, tileX, tileY); boolean[][] mask = mapData[row][col].getCollisionMask(); boolean b = mask == null || !mask[tileY][tileX]; @@ -152,36 +165,9 @@ public class GameMap { return b; } - private static int getCol(int x) { - return (x - OFFSET_X) / MAP_TILESIZE; - } - - private static int getRow(int y) { - return (y - OFFSET_Y) / MAP_TILESIZE; - } - - public int getHeight() { - return GamePanel.SCREEN_HEIGHT; - } - - public void removeTileImage(Point destination) { - int row = getRow(destination); - int col = getCol(destination); - MapTile tile = mapData[row][col]; - if(tile.getValue() == 0) tile.setImage(null); - } - - private static int getCol(Point point) { - return getCol(point.x); - } - - private static int getRow(Point point) { - return getRow(point.y); - } - public boolean isSolid(Point pos) { - int row = getRow(pos); - int col = getCol(pos); + int row = screenToRow(pos); + int col = screenToCol(pos); return isSolid(row,col); } @@ -194,11 +180,61 @@ public class GameMap { return solid; } - public int columns() { - return mapData[0].length; - } - public int rows() { - return mapData.length; + public void removeTileImage(Point destination) { + int row = screenToRow(destination); + int col = screenToCol(destination); + MapTile tile = mapData[row][col]; + if(tile.getValue() == 0) tile.setImage(null); } + private static int screenToCol(Point point) { + return screenToCol(point.x); + } + + private static int screenToRow(Point point) { + return screenToRow(point.y); + } + + public int columns() { + return MAP_COL_SIZE; + } + public int rows() { + return MAP_ROW_SIZE; + } + + public int colToWorldX(int col){ + return col * GameMap.MAP_TILESIZE + GameMap.OFFSET_X; + } + + public int rowToWorldY(int row){ + return row * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y; + } + + public int worldXtoCol(int x){ + return x / GameMap.MAP_TILESIZE; + } + + public int worldYtoRow(int y){ + return y / GameMap.MAP_TILESIZE; + } + + public Point coordToWorld(int row, int col){ + return new Point(colToWorldX(col), rowToWorldY(row)); + } + + public Point worldToScreen(Point world){ + return new Point(world.x + OFFSET_X, world.y + OFFSET_Y); + } + + public Point screenToWorld(Point screen){ + return new Point(screen.x - OFFSET_X, screen.y - OFFSET_Y); + } + + private static int screenToCol(int screenX) { + return (screenX - OFFSET_X) / MAP_TILESIZE; + } + + private static int screenToRow(int screenY) { + return (screenY - OFFSET_Y) / MAP_TILESIZE; + } }