GameOverState WIP

This commit is contained in:
Urban Modig
2025-09-01 21:48:34 +02:00
parent fcd686fad0
commit b13f87f77b
6 changed files with 168 additions and 37 deletions

View File

@ -12,17 +12,17 @@ import se.urmo.game.map.GameMap;
import se.urmo.game.map.MapTile;
import se.urmo.game.map.TileType;
import se.urmo.game.util.Direction;
import se.urmo.game.util.GameFonts;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.InputStream;
@Slf4j
public class PlayingState implements GameState {
public static final int REMAINING_LIVES = 0;
private final Game game;
private final GameStateManager gameStateManager;
private final Font arcadeFont;
private final GameOverState gameOverState;
// Core components
private final GhostManager ghostManager;
@ -34,9 +34,9 @@ public class PlayingState implements GameState {
private GameMap map;
// Durations (tune to taste)
private static final int READY_MS = 1500;
private static final int LEVEL_COMPLETE_MS= 1500;
private static final int LIFE_LOST_MS = 2000;
private static final int READY_MS = 1500;
private static final int LEVEL_COMPLETE_MS = 1500;
private static final int LIFE_LOST_MS = 2000;
// Score/Lives
private int score = 0;
@ -48,9 +48,10 @@ public class PlayingState implements GameState {
private long phaseStartMs = System.currentTimeMillis();
private boolean deathInProgress;
public PlayingState(Game game, GameStateManager gameStateManager) {
public PlayingState(Game game, GameStateManager gameStateManager, GameOverState gameOverState) {
this.game = game;
this.gameStateManager = gameStateManager;
this.gameOverState = gameOverState;
this.map = new GameMap("maps/map1.csv");
this.animationManager = new AnimationManager();
this.levelManager = new LevelManager();
@ -58,7 +59,6 @@ public class PlayingState implements GameState {
this.animationManager.register(pacman);
this.ghostManager = new GhostManager(new GhostCollisionChecker(map), animationManager, levelManager);
this.fruitManager = new FruitManager(levelManager);
this.arcadeFont = loadArcadeFont();
}
@Override
@ -88,16 +88,20 @@ public class PlayingState implements GameState {
case LIFE_LOST -> {
// Freeze, then reset round (keep dot state)
if (phaseElapsed() >= LIFE_LOST_MS) {
deathInProgress = false;
resetAfterLifeLost();
setPhase(RoundPhase.READY);
if (lives <= 0) {
endGame();
}
}
}
}
}
private void resetAfterLifeLost() {
pacman.reset(); // to start tile, direction stopped
ghostManager.reset(); // to house
pacman.reset(); // to start tile, direction stopped
ghostManager.reset(); // to house
}
private void advanceLevel() {
@ -122,14 +126,14 @@ public class PlayingState implements GameState {
Point pacmanScreenPos = pacman.getPosition();
MapTile tile = map.getTile(pacmanScreenPos);
boolean wasRemoved = map.removeTileImage(pacmanScreenPos);
if(wasRemoved && tile.getTileType() == TileType.LARGE_PELLET){
if (wasRemoved && tile.getTileType() == TileType.LARGE_PELLET) {
ghostManager.setFrightMode();
}
if(wasRemoved){
if (wasRemoved) {
dotsEaten++;
fruitManager.dotEaten(dotsEaten);
score+=tile.getTileType().getScore();
if(dotsEaten == map.numberOfDots()){
score += tile.getTileType().getScore();
if (dotsEaten == map.numberOfDots()) {
setPhase(RoundPhase.LEVEL_COMPLETE);
}
}
@ -153,17 +157,17 @@ public class PlayingState implements GameState {
}
private void drawCenterText(Graphics2D g, String text) {
g.setFont(arcadeFont.deriveFont(18F));
g.setFont(GameFonts.arcade(18F));
g.setColor(Color.YELLOW);
var fm = g.getFontMetrics();
int cx = GameMap.OFFSET_X + map.columns() * GameMap.MAP_TILESIZE/2;
int cy = GameMap.OFFSET_Y + map.rows() * GameMap.MAP_TILESIZE/2;
g.drawString(text, cx - fm.stringWidth(text)/2, cy);
int cx = GameMap.OFFSET_X + map.columns() * GameMap.MAP_TILESIZE / 2;
int cy = GameMap.OFFSET_Y + map.rows() * GameMap.MAP_TILESIZE / 2;
g.drawString(text, cx - fm.stringWidth(text) / 2, cy);
}
private void drawUI(Graphics2D g) {
g.setColor(Color.WHITE);
g.setFont(arcadeFont);
g.setFont(GameFonts.arcade(18F));
// Score (above map, left)
g.drawString("Your Score", 48, 48);
@ -202,6 +206,7 @@ public class PlayingState implements GameState {
private void checkCollisions() {
for (Ghost ghost : ghostManager.getGhosts()) {
if (deathInProgress) return; // guard
//if(overlap(pacman, ghost)
double dist = pacman.distanceTo(ghost.getPosition());
if (dist < GameMap.MAP_TILESIZE / 2.0) {
if (ghost.isFrightened()) {
@ -213,26 +218,24 @@ public class PlayingState implements GameState {
deathInProgress = true;
// Pac-Man loses a life
lives--;
if(lives >= REMAINING_LIVES)
setPhase(RoundPhase.LIFE_LOST);
else
endGame();
setPhase(RoundPhase.LIFE_LOST);
}
}
}
}
private void endGame() {
setPhase(RoundPhase.GAME_OVER);
gameStateManager.setState(GameStateType.GAME_OVER);
}
// private boolean overlaps(PacMan p, Ghost g) {
// // center-distance or AABB; center distance keeps the arcade feel
// double dx = p.getCenterX() - g.getCenterX();
// double dy = p.getCenterY() - g.getCenterY();
// double r = map.getTileSize() * 0.45; // tune threshold
// return (dx*dx + dy*dy) <= r*r;
// }
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);
}
private void endGame() {
gameOverState.setScore(score);
gameOverState.setLevel(levelManager.getCurrentLevel().getLevel());
gameStateManager.setState(GameStateType.GAME_OVER);
}
public void setScore(int score) {