Added visuals to RoundPhase
This commit is contained in:
@ -19,20 +19,35 @@ 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 GhostManager ghostManager;
|
||||
private final Font arcadeFont;
|
||||
|
||||
// Core components
|
||||
private final GhostManager ghostManager;
|
||||
private final FruitManager fruitManager;
|
||||
private final LevelManager levelManager;
|
||||
private final AnimationManager animationManager;
|
||||
private PacMan pacman;
|
||||
@Getter
|
||||
private GameMap map;
|
||||
private int score;
|
||||
|
||||
// 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;
|
||||
|
||||
// Score/Lives
|
||||
private int score = 0;
|
||||
private int lives = 3;
|
||||
private int dotsEaten = 0;
|
||||
|
||||
// Phase + timers
|
||||
private RoundPhase phase = RoundPhase.PLAYING;
|
||||
private long phaseStartMs = System.currentTimeMillis();
|
||||
private boolean deathInProgress;
|
||||
|
||||
public PlayingState(Game game, GameStateManager gameStateManager) {
|
||||
this.game = game;
|
||||
this.gameStateManager = gameStateManager;
|
||||
@ -48,12 +63,59 @@ public class PlayingState implements GameState {
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
animationManager.updateAll();
|
||||
pacman.update();
|
||||
ghostManager.update(pacman, map);
|
||||
fruitManager.update(pacman, this);
|
||||
checkCollisions();
|
||||
handleDots();
|
||||
switch (phase) {
|
||||
case READY -> {
|
||||
// Freeze everything during READY
|
||||
if (phaseElapsed() >= READY_MS) {
|
||||
setPhase(RoundPhase.PLAYING);
|
||||
}
|
||||
}
|
||||
case PLAYING -> {
|
||||
animationManager.updateAll();
|
||||
pacman.update();
|
||||
ghostManager.update(pacman, map);
|
||||
fruitManager.update(pacman, this);
|
||||
checkCollisions();
|
||||
handleDots();
|
||||
}
|
||||
case LEVEL_COMPLETE -> {
|
||||
// Freeze, then advance level
|
||||
if (phaseElapsed() >= LEVEL_COMPLETE_MS) {
|
||||
advanceLevel();
|
||||
setPhase(RoundPhase.READY);
|
||||
}
|
||||
}
|
||||
case LIFE_LOST -> {
|
||||
// Freeze, then reset round (keep dot state)
|
||||
if (phaseElapsed() >= LIFE_LOST_MS) {
|
||||
resetAfterLifeLost();
|
||||
setPhase(RoundPhase.READY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetAfterLifeLost() {
|
||||
pacman.reset(); // to start tile, direction stopped
|
||||
ghostManager.reset(); // to house
|
||||
}
|
||||
|
||||
private void advanceLevel() {
|
||||
levelManager.nextLevel();
|
||||
map.reset();
|
||||
ghostManager.reset();
|
||||
fruitManager.reset();
|
||||
pacman.reset();
|
||||
dotsEaten = 0;
|
||||
}
|
||||
|
||||
private void setPhase(RoundPhase next) {
|
||||
phase = next;
|
||||
phaseStartMs = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private long phaseElapsed() {
|
||||
return System.currentTimeMillis() - phaseStartMs;
|
||||
}
|
||||
|
||||
private void handleDots() {
|
||||
@ -68,12 +130,7 @@ public class PlayingState implements GameState {
|
||||
fruitManager.dotEaten(dotsEaten);
|
||||
score+=tile.getTileType().getScore();
|
||||
if(dotsEaten == map.numberOfDots()){
|
||||
levelManager.nextLevel();
|
||||
map.reset();
|
||||
ghostManager.reset();
|
||||
fruitManager.reset();
|
||||
pacman.resetPosition();
|
||||
dotsEaten = 0;
|
||||
setPhase(RoundPhase.LEVEL_COMPLETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,6 +142,23 @@ public class PlayingState implements GameState {
|
||||
ghostManager.draw(g);
|
||||
fruitManager.draw(g);
|
||||
drawUI(g);
|
||||
|
||||
// Phase overlays
|
||||
switch (phase) {
|
||||
case READY -> drawCenterText(g, "READY!");
|
||||
case LEVEL_COMPLETE -> drawCenterText(g, "LEVEL COMPLETE!");
|
||||
case LIFE_LOST -> drawCenterText(g, "LIFE LOST");
|
||||
default -> { /* no overlay */ }
|
||||
}
|
||||
}
|
||||
|
||||
private void drawCenterText(Graphics2D g, String text) {
|
||||
g.setFont(arcadeFont.deriveFont(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);
|
||||
}
|
||||
|
||||
private void drawUI(Graphics2D g) {
|
||||
@ -106,6 +180,7 @@ public class PlayingState implements GameState {
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (phase != RoundPhase.PLAYING) return;
|
||||
switch (e.getKeyCode()) {
|
||||
case KeyEvent.VK_W -> move(Direction.UP);
|
||||
case KeyEvent.VK_S -> move(Direction.DOWN);
|
||||
@ -126,6 +201,7 @@ public class PlayingState implements GameState {
|
||||
|
||||
private void checkCollisions() {
|
||||
for (Ghost ghost : ghostManager.getGhosts()) {
|
||||
if (deathInProgress) return; // guard
|
||||
double dist = pacman.distanceTo(ghost.getPosition());
|
||||
if (dist < GameMap.MAP_TILESIZE / 2.0) {
|
||||
if (ghost.isFrightened()) {
|
||||
@ -134,15 +210,23 @@ public class PlayingState implements GameState {
|
||||
ghost.resetPosition();
|
||||
ghost.setMode(GhostMode.CHASE); // end frightend
|
||||
} else {
|
||||
deathInProgress = true;
|
||||
// Pac-Man loses a life
|
||||
lives--;
|
||||
if(lives == 0)System.exit(1);
|
||||
else pacman.resetPosition();
|
||||
if(lives >= REMAINING_LIVES)
|
||||
setPhase(RoundPhase.LIFE_LOST);
|
||||
else
|
||||
endGame();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void endGame() {
|
||||
setPhase(RoundPhase.GAME_OVER);
|
||||
gameStateManager.setState(GameStateType.GAME_OVER);
|
||||
}
|
||||
|
||||
private Font loadArcadeFont() {
|
||||
try (InputStream is = getClass().getResourceAsStream("/fonts/PressStart2P-Regular.ttf")) {
|
||||
return Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(16f);
|
||||
|
||||
Reference in New Issue
Block a user