Compare commits
5 Commits
dc9dad4d9c
...
1f9e6f4e4a
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f9e6f4e4a | |||
| b9a43be3c6 | |||
| 9bb76ce682 | |||
| 712d58e8e3 | |||
| e8112f1cbb |
@ -65,8 +65,4 @@ public class CollisionChecker {
|
||||
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
public void removeTile(Point destination) {
|
||||
map.removeTileImage(destination);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import java.awt.Point;
|
||||
public class BlinkyStrategy implements GhostStrategy {
|
||||
@Override
|
||||
public Point chooseTarget(Ghost ghost, PacMan pacman, GameMap map) {
|
||||
return pacman.getTilePosition();
|
||||
return pacman.getPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import java.awt.Point;
|
||||
public class ClydeStrategy implements GhostStrategy {
|
||||
@Override
|
||||
public Point chooseTarget(Ghost clyde, PacMan pacman, GameMap map) {
|
||||
Point pacTile = pacman.getTilePosition();
|
||||
Point pacTile = pacman.getPosition();
|
||||
Point clydeTile = clyde.getPosition(); // ghost’s current tile
|
||||
|
||||
double distance = pacTile.distance(clydeTile);
|
||||
|
||||
@ -27,6 +27,7 @@ public class Ghost {
|
||||
|
||||
private final GhostCollisionChecker collisionChecker;
|
||||
private final GhostStrategy chaseStrategy;
|
||||
private final Point startPos;
|
||||
@Getter
|
||||
private Point position;
|
||||
|
||||
@ -50,7 +51,7 @@ public class Ghost {
|
||||
position = new Point(
|
||||
13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_X + (GameMap.MAP_TILESIZE / 2),
|
||||
4 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + (GameMap.MAP_TILESIZE / 2) );
|
||||
|
||||
startPos = position;
|
||||
this.currentStrategy = chaseStrategy;
|
||||
}
|
||||
|
||||
@ -74,30 +75,58 @@ public class Ghost {
|
||||
}
|
||||
|
||||
private void updatePosition(PacMan pacman, GameMap map) {
|
||||
// only move ghost on update interval - this is basically ghost speed;
|
||||
if (movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) {
|
||||
if (isAlligned(position)) {
|
||||
log.info("Evaluating possible directions");
|
||||
prevDirection = direction;
|
||||
direction = chooseDirection(
|
||||
prioritize(collisionChecker.calculateDirectionAlternatives(position)),
|
||||
currentStrategy.chooseTarget(this, pacman, map));
|
||||
log.info("selecting direction {}", direction);
|
||||
}
|
||||
chooseDirection(pacman, map);
|
||||
|
||||
Point newPosition = new Point(
|
||||
position.x + direction.dx,
|
||||
position.y + direction.dy);
|
||||
log.debug("Next position {}", newPosition);
|
||||
Point newPosition = getNewPosition();
|
||||
|
||||
Point destination = collisionChecker.canMoveTo(direction, newPosition);
|
||||
move(newPosition);
|
||||
|
||||
if (destination != null) {
|
||||
position = destination;
|
||||
}
|
||||
movementTick = 0;
|
||||
} else movementTick++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a position and a direction - calculate the new position
|
||||
*
|
||||
* @return new position
|
||||
*/
|
||||
private Point getNewPosition() {
|
||||
Point point = new Point(
|
||||
position.x + direction.dx,
|
||||
position.y + direction.dy);
|
||||
//log.debug("Next position {}", point);
|
||||
return point;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose a new direction when 'aligned' ie when in the exact middle of a tile
|
||||
* else continue with the existing direction.
|
||||
*
|
||||
* @param pacman
|
||||
* @param map
|
||||
*/
|
||||
private void chooseDirection(PacMan pacman, GameMap map) {
|
||||
if (isAlligned(position)) {
|
||||
log.info("Evaluating possible directions");
|
||||
prevDirection = direction;
|
||||
direction = chooseDirection(
|
||||
prioritize(collisionChecker.calculateDirectionAlternatives(position)),
|
||||
currentStrategy.chooseTarget(this, pacman, map));
|
||||
log.info("selecting direction {}", direction);
|
||||
}
|
||||
}
|
||||
|
||||
private void move(Point newPosition) {
|
||||
Point destination = collisionChecker.canMoveTo(direction, newPosition);
|
||||
|
||||
if (destination != null) {
|
||||
position = destination;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Direction, Integer> prioritize(List<Direction> directions) {
|
||||
return directions.stream()
|
||||
.filter(d -> d != Direction.NONE)
|
||||
@ -167,4 +196,11 @@ public class Ghost {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFrightened() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void resetPosition() {
|
||||
position = startPos;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ public class InkyStrategy implements GhostStrategy {
|
||||
public Point chooseTarget(Ghost ghost, PacMan pacman, GameMap map) {
|
||||
// 1. Two tiles ahead of pacman
|
||||
Direction pacmanDir = pacman.getDirection();
|
||||
Point pacmanPos = pacman.getTilePosition();
|
||||
Point pacmanPos = pacman.getPosition();
|
||||
Point ahead = switch (pacmanDir){
|
||||
case RIGHT -> new Point(pacmanPos.x + 8 * GameMap.MAP_TILESIZE, pacmanPos.y);
|
||||
case LEFT -> new Point(pacmanPos.x - 8 * GameMap.MAP_TILESIZE, pacmanPos.y);
|
||||
|
||||
@ -22,6 +22,7 @@ public class PacMan {
|
||||
private static final int COLLISION_BOX_SIZE = 16;
|
||||
private static final int COLLISION_BOX_OFFSET = (PACMAN_SIZE - COLLISION_BOX_SIZE) / 2;
|
||||
private final Game game;
|
||||
private final Point startPosition;
|
||||
private int aniTick = 0;
|
||||
private int aniIndex = 0;
|
||||
private static final int ANIMATION_UPDATE_FREQUENCY = 10;
|
||||
@ -29,6 +30,7 @@ public class PacMan {
|
||||
@Setter
|
||||
private boolean moving;
|
||||
private final BufferedImage[][] movmentImages = new BufferedImage[4][4];
|
||||
@Getter
|
||||
private Point position;
|
||||
private static final BufferedImage COLLISION_BOX = MiscUtil.createOutlinedBox(COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, Color.yellow, 2);
|
||||
private final CollisionChecker collisionChecker;
|
||||
@ -39,9 +41,10 @@ public class PacMan {
|
||||
public PacMan(Game game, CollisionChecker collisionChecker) {
|
||||
this.game = game;
|
||||
this.collisionChecker = collisionChecker;
|
||||
position = new Point(
|
||||
this.position = new Point(
|
||||
26 * GameMap.MAP_TILESIZE + GameMap.OFFSET_X,
|
||||
13 * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y + (GameMap.MAP_TILESIZE / 2));
|
||||
this.startPosition = this.position;
|
||||
loadAnimation();
|
||||
}
|
||||
|
||||
@ -80,21 +83,21 @@ public class PacMan {
|
||||
|
||||
public void update() {
|
||||
updateAnimationTick();
|
||||
if(direction == Direction.NONE) return;
|
||||
//if(direction == Direction.NONE) return;
|
||||
if(moving) {
|
||||
Point newPosition = switch (direction) {
|
||||
case RIGHT -> new Point(position.x + speed, position.y);
|
||||
case LEFT -> new Point(position.x - speed, position.y);
|
||||
case UP -> new Point(position.x, position.y - speed);
|
||||
case DOWN -> new Point(position.x, position.y + speed);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + direction);
|
||||
};
|
||||
log.debug("At: {},trying to move {} to {}", position, direction.name(), newPosition);
|
||||
Point destination = collisionChecker.getValidDestination(direction, newPosition, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE);
|
||||
|
||||
Point newPosition = switch (direction){
|
||||
case RIGHT -> new Point(position.x + speed, position.y);
|
||||
case LEFT -> new Point(position.x - speed, position.y);
|
||||
case UP -> new Point(position.x , position.y - speed);
|
||||
case DOWN -> new Point(position.x, position.y + speed);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + direction);
|
||||
};
|
||||
log.debug("At: {},trying to move {} to {}", position, direction.name(), newPosition);
|
||||
Point destination = collisionChecker.getValidDestination(direction, newPosition, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE);
|
||||
|
||||
if(destination != null) {
|
||||
collisionChecker.removeTile(destination);
|
||||
position = destination;
|
||||
if (destination != null) {
|
||||
position = destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,7 +115,19 @@ public class PacMan {
|
||||
}
|
||||
}
|
||||
|
||||
public Point getTilePosition() {
|
||||
return position;
|
||||
public double distanceTo(Point point) {
|
||||
return position.distance(point);
|
||||
}
|
||||
|
||||
public void loseLife() {
|
||||
|
||||
}
|
||||
|
||||
public void resetPosition() {
|
||||
position = startPosition;
|
||||
}
|
||||
|
||||
public Image getLifeIcon() {
|
||||
return movmentImages[0][1];
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ public class PinkyStrategy implements GhostStrategy{
|
||||
@Override
|
||||
public Point chooseTarget(Ghost ghost, PacMan pacman, GameMap map) {
|
||||
Direction pacmanDir = pacman.getDirection();
|
||||
Point pacmanPos = pacman.getTilePosition();
|
||||
Point pacmanPos = pacman.getPosition();
|
||||
return switch (pacmanDir){
|
||||
case RIGHT -> new Point(pacmanPos.x + 8 * GameMap.MAP_TILESIZE, pacmanPos.y);
|
||||
case LEFT -> new Point(pacmanPos.x - 8 * GameMap.MAP_TILESIZE, pacmanPos.y);
|
||||
|
||||
@ -16,41 +16,43 @@ public class GameMap {
|
||||
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 final BufferedImage[][] mapSpriteBuffer;
|
||||
private final MapTile[][] mapData;
|
||||
private final BufferedImage[][] mapItemSpriteBuffer;
|
||||
|
||||
public GameMap() {
|
||||
loadSprites();
|
||||
mapData = loadMap("maps/map1.csv");
|
||||
this.mapSpriteBuffer = LoadSave.loadSprites("sprites/PacMan-custom-spritemap-0-3.png", 5, 11, MAP_TILESIZE);
|
||||
this.mapItemSpriteBuffer = LoadSave.loadSprites("sprites/PacManAssets-Items.png", 2, 8, MAP_TILESIZE);
|
||||
this.mapData = loadMap("maps/map1.csv", MAP_ROW_SIZE, MAP_COL_SIZE);
|
||||
}
|
||||
|
||||
private MapTile[][] loadMap(String path) {
|
||||
MapTile[][] data = new MapTile[MAP_ROW_SIZE][MAP_COL_SIZE];
|
||||
private MapTile[][] loadMap(String path, int mapRowSize, int mapColSize) {
|
||||
MapTile[][] data = new MapTile[mapRowSize][mapColSize];
|
||||
|
||||
try (InputStream is = getClass().getClassLoader().getResourceAsStream(path);
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) {
|
||||
|
||||
String line;
|
||||
int rowIndex = 0;
|
||||
while ((line = br.readLine()) != null && rowIndex < MAP_ROW_SIZE) {
|
||||
while ((line = br.readLine()) != null && rowIndex < mapRowSize) {
|
||||
String[] tokens = line.split(",");
|
||||
if (tokens.length != MAP_COL_SIZE) {
|
||||
if (tokens.length != mapColSize) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid map format: row " + rowIndex + " has " + tokens.length +
|
||||
" columns, expected " + MAP_COL_SIZE
|
||||
" columns, expected " + mapColSize
|
||||
);
|
||||
}
|
||||
|
||||
for (int col = 0; col < MAP_COL_SIZE; col++) {
|
||||
for (int col = 0; col < mapColSize; col++) {
|
||||
int value = Integer.parseInt(tokens[col].trim());
|
||||
data[rowIndex][col] = new MapTile(getSprite(value), value);
|
||||
}
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
if (rowIndex != MAP_ROW_SIZE) {
|
||||
if (rowIndex != mapRowSize) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid map format: found " + rowIndex + " rows, expected " + MAP_ROW_SIZE
|
||||
"Invalid map format: found " + rowIndex + " rows, expected " + mapRowSize
|
||||
);
|
||||
}
|
||||
|
||||
@ -64,76 +66,67 @@ public class GameMap {
|
||||
|
||||
private BufferedImage getSprite(int value) {
|
||||
return switch (value){
|
||||
case 0 -> images[1][1];
|
||||
case 1 -> images[0][0];
|
||||
case 2 -> images[0][1];
|
||||
case 3 -> images[0][2];
|
||||
case 4 -> images[0][3];
|
||||
case 5 -> images[0][4];
|
||||
case 6 -> images[0][5];
|
||||
case 7 -> images[0][6];
|
||||
case 8 -> images[0][7];
|
||||
case 9 -> images[0][8];
|
||||
case 10 -> images[0][9];
|
||||
case 11 -> images[0][10];
|
||||
case 12 -> images[1][0];
|
||||
case 13 -> images[1][1];
|
||||
case 14 -> images[1][2];
|
||||
case 15 -> images[1][3];
|
||||
case 16 -> images[1][4];
|
||||
case 17 -> images[1][5];
|
||||
case 18 -> images[1][6];
|
||||
case 19 -> images[1][7];
|
||||
case 20 -> images[1][8];
|
||||
case 21 -> images[1][9];
|
||||
case 22 -> images[1][10];
|
||||
case 23 -> images[2][0];
|
||||
case 24 -> images[2][1];
|
||||
case 25 -> images[2][2];
|
||||
case 26 -> images[2][3];
|
||||
case 27 -> images[2][4];
|
||||
case 28 -> images[2][5];
|
||||
case 29 -> images[2][6];
|
||||
case 30 -> images[2][7];
|
||||
case 31 -> images[2][8];
|
||||
case 32 -> images[2][9];
|
||||
case 33 -> images[2][10];
|
||||
case 34 -> images[3][0];
|
||||
case 35 -> images[3][1];
|
||||
case 36 -> images[3][2];
|
||||
case 37 -> images[3][3];
|
||||
case 38 -> images[3][4];
|
||||
case 39 -> images[3][5];
|
||||
case 40 -> images[3][6];
|
||||
case 41 -> images[3][7];
|
||||
case 42 -> images[3][8];
|
||||
case 43 -> images[3][9];
|
||||
case 44 -> images[3][10];
|
||||
case 45 -> images[4][0];
|
||||
case 46 -> images[4][1];
|
||||
case 47 -> images[4][2];
|
||||
case 48 -> images[4][3];
|
||||
case 49 -> images[4][4];
|
||||
case 50 -> images[4][5];
|
||||
case 51 -> images[4][6];
|
||||
case 52 -> images[4][7];
|
||||
case 53 -> images[4][8];
|
||||
case 54 -> images[4][9];
|
||||
case 55 -> images[4][10];
|
||||
case 0 -> mapSpriteBuffer[1][1];
|
||||
case 1 -> mapSpriteBuffer[0][0];
|
||||
case 2 -> mapSpriteBuffer[0][1];
|
||||
case 3 -> mapSpriteBuffer[0][2];
|
||||
case 4 -> mapSpriteBuffer[0][3];
|
||||
case 5 -> mapSpriteBuffer[0][4];
|
||||
case 6 -> mapSpriteBuffer[0][5];
|
||||
case 7 -> mapSpriteBuffer[0][6];
|
||||
case 8 -> mapSpriteBuffer[0][7];
|
||||
case 9 -> mapSpriteBuffer[0][8];
|
||||
case 10 -> mapSpriteBuffer[0][9];
|
||||
case 11 -> mapSpriteBuffer[0][10];
|
||||
case 12 -> mapSpriteBuffer[1][0];
|
||||
case 13 -> mapSpriteBuffer[1][1];
|
||||
case 14 -> mapSpriteBuffer[1][2];
|
||||
case 15 -> mapSpriteBuffer[1][3];
|
||||
case 16 -> mapSpriteBuffer[1][4];
|
||||
case 17 -> mapSpriteBuffer[1][5];
|
||||
case 18 -> mapSpriteBuffer[1][6];
|
||||
case 19 -> mapSpriteBuffer[1][7];
|
||||
case 20 -> mapSpriteBuffer[1][8];
|
||||
case 21 -> mapSpriteBuffer[1][9];
|
||||
case 22 -> mapSpriteBuffer[1][10];
|
||||
case 23 -> mapSpriteBuffer[2][0];
|
||||
case 24 -> mapSpriteBuffer[2][1];
|
||||
case 25 -> mapSpriteBuffer[2][2];
|
||||
case 26 -> mapSpriteBuffer[2][3];
|
||||
case 27 -> mapSpriteBuffer[2][4];
|
||||
case 28 -> mapSpriteBuffer[2][5];
|
||||
case 29 -> mapSpriteBuffer[2][6];
|
||||
case 30 -> mapSpriteBuffer[2][7];
|
||||
case 31 -> mapSpriteBuffer[2][8];
|
||||
case 32 -> mapSpriteBuffer[2][9];
|
||||
case 33 -> mapSpriteBuffer[2][10];
|
||||
case 34 -> mapSpriteBuffer[3][0];
|
||||
case 35 -> mapSpriteBuffer[3][1];
|
||||
case 36 -> mapSpriteBuffer[3][2];
|
||||
case 37 -> mapSpriteBuffer[3][3];
|
||||
case 38 -> mapSpriteBuffer[3][4];
|
||||
case 39 -> mapSpriteBuffer[3][5];
|
||||
case 40 -> mapSpriteBuffer[3][6];
|
||||
case 41 -> mapSpriteBuffer[3][7];
|
||||
case 42 -> mapSpriteBuffer[3][8];
|
||||
case 43 -> mapSpriteBuffer[3][9];
|
||||
case 44 -> mapSpriteBuffer[3][10];
|
||||
case 45 -> mapSpriteBuffer[4][0];
|
||||
case 46 -> mapSpriteBuffer[4][1];
|
||||
case 47 -> mapSpriteBuffer[4][2];
|
||||
case 48 -> mapSpriteBuffer[4][3];
|
||||
case 49 -> mapSpriteBuffer[4][4];
|
||||
case 50 -> mapSpriteBuffer[4][5];
|
||||
case 51 -> mapSpriteBuffer[4][6];
|
||||
case 52 -> mapSpriteBuffer[4][7];
|
||||
case 53 -> mapSpriteBuffer[4][8];
|
||||
case 54 -> mapSpriteBuffer[4][9];
|
||||
case 55 -> mapSpriteBuffer[4][10];
|
||||
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private void loadSprites() {
|
||||
BufferedImage img = LoadSave.GetSpriteAtlas("sprites/PacMan-custom-spritemap-0-3.png");//473B78
|
||||
for (int row = 0; row < 5; row++) {
|
||||
for (int col = 0; col < 11; col++) {
|
||||
images[row][col] = img.getSubimage(MAP_TILESIZE * col, MAP_TILESIZE * row, MAP_TILESIZE, MAP_TILESIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Graphics g) {
|
||||
for (int row = 0; row < mapData.length; row++) {
|
||||
for (int col = 0; col < mapData[row].length; col++) {
|
||||
@ -176,15 +169,30 @@ public class GameMap {
|
||||
if (col >= columns() || col < 0 ) return true;
|
||||
MapTile mapTile = mapData[row][col];
|
||||
boolean solid = mapTile.isSolid();
|
||||
log.debug("[{}][{}] is {} ({})", row, col, solid ? "solid" : " not solid", mapTile.getValue());
|
||||
// log.debug("[{}][{}] is {} ({})", row, col, solid ? "solid" : " not solid", mapTile.getValue());
|
||||
return solid;
|
||||
}
|
||||
|
||||
public void removeTileImage(Point destination) {
|
||||
int row = screenToRow(destination);
|
||||
int col = screenToCol(destination);
|
||||
public boolean removeTileImage(Point screen) {
|
||||
if (screen == null || mapData == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int row = screenToRow(screen);
|
||||
int col = screenToCol(screen);
|
||||
|
||||
if (row < 0 || row >= mapData.length || col < 0 || col >= mapData[0].length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MapTile tile = mapData[row][col];
|
||||
if(tile.getValue() == 0) tile.setImage(null);
|
||||
if (tile != null && tile.getValue() == 0 && tile.getImage() != null) {
|
||||
tile.setImage(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private static int screenToCol(Point point) {
|
||||
@ -230,11 +238,12 @@ public class GameMap {
|
||||
return new Point(screen.x - OFFSET_X, screen.y - OFFSET_Y);
|
||||
}
|
||||
|
||||
private static int screenToCol(int screenX) {
|
||||
public static int screenToCol(int screenX) {
|
||||
return (screenX - OFFSET_X) / MAP_TILESIZE;
|
||||
}
|
||||
|
||||
private static int screenToRow(int screenY) {
|
||||
public static int screenToRow(int screenY) {
|
||||
return (screenY - OFFSET_Y) / MAP_TILESIZE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -50,8 +50,7 @@ public class GhostManager {
|
||||
ghosts.add(blinky);
|
||||
ghosts.add(new Ghost(ghostCollisionChecker, new PinkyStrategy(),new ScatterToTopLeft(), image[2]));
|
||||
ghosts.add(new Ghost(ghostCollisionChecker,new InkyStrategy(blinky), new ScatterToBottomRight(), image[1]));
|
||||
Ghost clyde = new Ghost(ghostCollisionChecker, new ClydeStrategy(), new ScatterToBottomLeft(), image[3]);
|
||||
ghosts.add(clyde);
|
||||
ghosts.add(new Ghost(ghostCollisionChecker, new ClydeStrategy(), new ScatterToBottomLeft(), image[3]));
|
||||
setMode(GhostMode.CHASE);
|
||||
}
|
||||
|
||||
@ -68,7 +67,7 @@ public class GhostManager {
|
||||
|
||||
public void setMode(GhostMode mode) {
|
||||
this.globalMode = mode;
|
||||
log.debug("Mode changed to {}", globalMode);
|
||||
log.info("Mode changed to {}", globalMode);
|
||||
for (Ghost g : ghosts) {
|
||||
g.setMode(mode);
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package se.urmo.game.state;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import se.urmo.game.collision.CollisionChecker;
|
||||
import se.urmo.game.collision.GhostCollisionChecker;
|
||||
import se.urmo.game.entities.BlinkyStrategy;
|
||||
import se.urmo.game.entities.Ghost;
|
||||
import se.urmo.game.entities.PacMan;
|
||||
import se.urmo.game.main.Game;
|
||||
@ -12,14 +12,19 @@ import se.urmo.game.util.Direction;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.InputStream;
|
||||
|
||||
@Slf4j
|
||||
public class PlayingState implements GameState {
|
||||
private final Game game;
|
||||
private final GameStateManager gameStateManager;
|
||||
private final GhostManager ghostManager;
|
||||
private final Font arcadeFont;
|
||||
private PacMan pacman;
|
||||
@Getter
|
||||
private GameMap map;
|
||||
private int score;
|
||||
private int lives = 3;
|
||||
|
||||
public PlayingState(Game game, GameStateManager gameStateManager) {
|
||||
this.game = game;
|
||||
@ -27,12 +32,24 @@ public class PlayingState implements GameState {
|
||||
this.map = new GameMap();
|
||||
this.pacman = new PacMan(game, new CollisionChecker(map));
|
||||
this.ghostManager = new GhostManager(new GhostCollisionChecker(map));
|
||||
this.arcadeFont = loadArcadeFont();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
pacman.update();
|
||||
ghostManager.update(pacman, map);
|
||||
checkCollisions();
|
||||
handleDots();
|
||||
}
|
||||
|
||||
private void handleDots() {
|
||||
Point pacmanScreenPos = pacman.getPosition();
|
||||
boolean wasRemoved = map.removeTileImage(pacmanScreenPos);
|
||||
|
||||
if(wasRemoved){
|
||||
score+=10;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -40,6 +57,24 @@ public class PlayingState implements GameState {
|
||||
map.draw(g);
|
||||
pacman.draw(g);
|
||||
ghostManager.draw(g);
|
||||
drawUI(g);
|
||||
}
|
||||
|
||||
private void drawUI(Graphics2D g) {
|
||||
g.setColor(Color.WHITE);
|
||||
g.setFont(arcadeFont);
|
||||
|
||||
// Score (above map, left)
|
||||
g.drawString("Your Score", 48, 48);
|
||||
g.drawString("" + score, 48, 72);
|
||||
|
||||
// Lives (below map, left)
|
||||
for (int i = 1; i < lives; i++) {
|
||||
g.drawImage(pacman.getLifeIcon(),
|
||||
6 * GameMap.OFFSET_X - i * 24,
|
||||
map.rows() * GameMap.MAP_TILESIZE + GameMap.OFFSET_Y,
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,6 +95,31 @@ public class PlayingState implements GameState {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
pacman.setMoving(false);
|
||||
pacman.setDirection(Direction.NONE);
|
||||
}
|
||||
|
||||
private void checkCollisions() {
|
||||
for (Ghost ghost : ghostManager.getGhosts()) {
|
||||
double dist = pacman.distanceTo(ghost.getPosition());
|
||||
if (dist < GameMap.MAP_TILESIZE / 2.0) {
|
||||
if (ghost.isFrightened()) {
|
||||
// Pac-Man eats ghost
|
||||
score += 200;
|
||||
ghost.resetPosition();
|
||||
} else {
|
||||
// Pac-Man loses a life
|
||||
lives--;
|
||||
if(lives == 0)System.exit(1);
|
||||
else pacman.resetPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Font loadArcadeFont() {
|
||||
try (InputStream is = getClass().getResourceAsStream("/fonts/PressStart2P-Regular.ttf")) {
|
||||
return Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(16f);
|
||||
} catch (Exception e) {
|
||||
return new Font("Monospaced", Font.BOLD, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,21 @@ import java.io.InputStream;
|
||||
|
||||
public class LoadSave {
|
||||
|
||||
|
||||
public static BufferedImage[][] loadSprites(final String fileName, final int rows, final int columns, int mapTilesize) {
|
||||
BufferedImage spriteSheet = LoadSave.GetSpriteAtlas(fileName);
|
||||
if(spriteSheet.getHeight() != rows * mapTilesize) throw new IllegalStateException("Wrong sprite row size");
|
||||
if(spriteSheet.getWidth() != columns * mapTilesize) throw new IllegalStateException("Wrong sprite colum size");
|
||||
BufferedImage[][] spriteBuffer = new BufferedImage[rows][columns];
|
||||
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < columns; col++) {
|
||||
spriteBuffer[row][col] = spriteSheet.getSubimage(mapTilesize * col, mapTilesize * row, mapTilesize, mapTilesize);
|
||||
}
|
||||
}
|
||||
return spriteBuffer;
|
||||
}
|
||||
|
||||
public static BufferedImage GetSpriteAtlas(String fileName) {
|
||||
BufferedImage img = null;
|
||||
InputStream is = LoadSave.class.getResourceAsStream("/" + fileName);
|
||||
|
||||
BIN
src/main/resources/fonts/PressStart2P-Regular.ttf
Normal file
BIN
src/main/resources/fonts/PressStart2P-Regular.ttf
Normal file
Binary file not shown.
Reference in New Issue
Block a user