Fixing minor improvements

This commit is contained in:
Urban Modig
2025-08-21 13:50:22 +02:00
parent d06e7131ad
commit dc9dad4d9c
3 changed files with 105 additions and 68 deletions

View File

@ -19,7 +19,6 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class Ghost { public class Ghost {
private static final int COLLISION_BOX_SIZE = 16; private static final int COLLISION_BOX_SIZE = 16;
private static final int GHOST_SPEED = 1;
private static final int GHOST_MOVEMENT_UPDATE_FREQUENCY = 2; private static final int GHOST_MOVEMENT_UPDATE_FREQUENCY = 2;
public static final int GHOST_SIZE = 32; public static final int GHOST_SIZE = 32;
private static final int ANIMATION_UPDATE_FREQUENCY = 25; private static final int ANIMATION_UPDATE_FREQUENCY = 25;
@ -49,8 +48,8 @@ public class Ghost {
this.scaterStrategy = scaterStrategy; this.scaterStrategy = scaterStrategy;
this.animation = animation; this.animation = animation;
position = new Point( position = new Point(
13 * GameMap.MAP_TILESIZE + (GameMap.MAP_TILESIZE / 2) + GameMap.OFFSET_X, 13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_X + (GameMap.MAP_TILESIZE / 2),
4 * GameMap.MAP_TILESIZE + (GameMap.MAP_TILESIZE / 2) + GameMap.OFFSET_Y); 4 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + (GameMap.MAP_TILESIZE / 2) );
this.currentStrategy = chaseStrategy; this.currentStrategy = chaseStrategy;
} }
@ -86,8 +85,8 @@ public class Ghost {
} }
Point newPosition = new Point( Point newPosition = new Point(
position.x + direction.dx * GHOST_SPEED, position.x + direction.dx,
position.y + direction.dy * GHOST_SPEED); position.y + direction.dy);
log.debug("Next position {}", newPosition); log.debug("Next position {}", newPosition);
Point destination = collisionChecker.canMoveTo(direction, newPosition); Point destination = collisionChecker.canMoveTo(direction, newPosition);
@ -124,15 +123,15 @@ public class Ghost {
.orElse(Integer.MAX_VALUE); .orElse(Integer.MAX_VALUE);
// Return all directions that have this priority // Return all directions that have this priority
List<Direction> l = options.entrySet().stream() List<Direction> directions = options.entrySet().stream()
.filter(entry -> entry.getValue() == lowestPriority) .filter(entry -> entry.getValue() == lowestPriority)
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.toList(); .toList();
Direction best = l.getFirst(); Direction best = directions.getFirst();
double bestDist = Double.MAX_VALUE; double bestDist = Double.MAX_VALUE;
for (Direction d : l) { for (Direction d : directions) {
int nx = position.x + d.dx * GameMap.MAP_TILESIZE; int nx = position.x + d.dx * GameMap.MAP_TILESIZE;
int ny = position.y + d.dy * GameMap.MAP_TILESIZE; int ny = position.y + d.dy * GameMap.MAP_TILESIZE;
double dist = target.distance(nx, ny); double dist = target.distance(nx, ny);

View File

@ -7,6 +7,8 @@ import java.awt.Point;
public class ScatterToBottomRight implements GhostStrategy { public class ScatterToBottomRight implements GhostStrategy {
@Override @Override
public Point chooseTarget(Ghost ghost, PacMan pacman, GameMap map) { 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));
} }
} }

View File

@ -1,53 +1,65 @@
package se.urmo.game.map; package se.urmo.game.map;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import se.urmo.game.main.GamePanel;
import se.urmo.game.util.LoadSave; import se.urmo.game.util.LoadSave;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.*; import java.io.*;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.IntStream;
@Slf4j @Slf4j
public class GameMap { public class GameMap {
public static final int MAP_TILESIZE = 16;// 16px from left 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_Y = 7 * MAP_TILESIZE; // 160px from top
public static final int OFFSET_X = MAP_TILESIZE; // 16px from left public static final int OFFSET_X = MAP_TILESIZE; // 16px from left
private final BufferedImage[][] images = new BufferedImage[13][19]; private final BufferedImage[][] images = new BufferedImage[13][19];
private MapTile[][] mapData; private final MapTile[][] mapData;
public GameMap() { public GameMap() {
loadSprites(); loadSprites();
loadMap("maps/map1.csv"); mapData = loadMap("maps/map1.csv");
} }
private void loadMap(String path) { private MapTile[][] loadMap(String path) {
List<int[]> rows = new ArrayList<>(); MapTile[][] data = new MapTile[MAP_ROW_SIZE][MAP_COL_SIZE];
try (InputStream is = getClass().getClassLoader().getResourceAsStream(path); try (InputStream is = getClass().getClassLoader().getResourceAsStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) { BufferedReader br = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) {
String line; String line;
while ((line = br.readLine()) != null) { int rowIndex = 0;
while ((line = br.readLine()) != null && rowIndex < MAP_ROW_SIZE) {
String[] tokens = line.split(","); String[] tokens = line.split(",");
int[] row = new int[tokens.length]; if (tokens.length != MAP_COL_SIZE) {
for (int i = 0; i < tokens.length; i++) { throw new IllegalStateException(
row[i] = Integer.parseInt(tokens[i].trim()); "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) { if (rowIndex != MAP_ROW_SIZE) {
e.printStackTrace(); 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() return data;
.map(row -> IntStream.of(row)
.mapToObj(value -> new MapTile(getSprite(value), value))
.toArray(MapTile[]::new))
.toArray(MapTile[][]::new);
} }
private BufferedImage getSprite(int value) { private BufferedImage getSprite(int value) {
@ -139,12 +151,13 @@ public class GameMap {
public boolean isPassable(List<Point> list){ public boolean isPassable(List<Point> list){
return list.stream().allMatch(p -> isPassable(p.x, p.y)); return list.stream().allMatch(p -> isPassable(p.x, p.y));
} }
public boolean isPassable(int x, int y) {
int row = getRow(y); public boolean isPassable(int screenX, int screenY) {
int col = getCol(x); int row = screenToRow(screenY);
int tileY = (y - OFFSET_Y) % MAP_TILESIZE; int col = screenToCol(screenX);
int tileX = (x - OFFSET_X) % MAP_TILESIZE; int tileY = (screenY - OFFSET_Y) % MAP_TILESIZE;
log.trace("Point[x="+x+",y="+y+"] is row="+ row + ", col=" + col + " with reminder x=" +tileX+",y=" +tileY); 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[][] mask = mapData[row][col].getCollisionMask();
boolean b = mask == null || !mask[tileY][tileX]; boolean b = mask == null || !mask[tileY][tileX];
@ -152,36 +165,9 @@ public class GameMap {
return b; 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) { public boolean isSolid(Point pos) {
int row = getRow(pos); int row = screenToRow(pos);
int col = getCol(pos); int col = screenToCol(pos);
return isSolid(row,col); return isSolid(row,col);
} }
@ -194,11 +180,61 @@ public class GameMap {
return solid; return solid;
} }
public int columns() { public void removeTileImage(Point destination) {
return mapData[0].length; int row = screenToRow(destination);
} int col = screenToCol(destination);
public int rows() { MapTile tile = mapData[row][col];
return mapData.length; 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;
}
} }