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
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<Direction> l = options.entrySet().stream()
List<Direction> 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);

View File

@ -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));
}
}

View File

@ -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<int[]> 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());
}
rows.add(row);
if (tokens.length != MAP_COL_SIZE) {
throw new IllegalStateException(
"Invalid map format: row " + rowIndex + " has " + tokens.length +
" columns, expected " + MAP_COL_SIZE
);
}
} catch (IOException | NullPointerException e) {
e.printStackTrace();
for (int col = 0; col < MAP_COL_SIZE; col++) {
int value = Integer.parseInt(tokens[col].trim());
data[rowIndex][col] = new MapTile(getSprite(value), value);
}
mapData = rows.stream()
.map(row -> IntStream.of(row)
.mapToObj(value -> new MapTile(getSprite(value), value))
.toArray(MapTile[]::new))
.toArray(MapTile[][]::new);
rowIndex++;
}
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);
}
return data;
}
private BufferedImage getSprite(int value) {
@ -139,12 +151,13 @@ public class GameMap {
public boolean isPassable(List<Point> 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;
}
}