Added visuals to RoundPhase
This commit is contained in:
@ -219,4 +219,8 @@ public class Ghost extends BaseAnimated {
|
||||
public Point getPosition() {
|
||||
return new Point((int) position.x, (int) position.y);
|
||||
}
|
||||
|
||||
public void resetModes() {
|
||||
mode = GhostMode.CHASE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,6 +109,11 @@ public class PacMan extends BaseAnimated {
|
||||
position = startPosition;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
resetPosition();
|
||||
aniIndex = 0; // reset animation to start
|
||||
}
|
||||
|
||||
public Image getLifeIcon() {
|
||||
return spriteSheets[0][1];
|
||||
}
|
||||
|
||||
@ -253,7 +253,7 @@ public class GameMap {
|
||||
|
||||
public long numberOfDots() {
|
||||
//return this.numberOfDots;
|
||||
return 10;
|
||||
return 50;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
|
||||
@ -19,7 +19,7 @@ public class GameStateManager {
|
||||
setState(GameStateType.PLAYING);
|
||||
}
|
||||
|
||||
private void setState(GameStateType type) {
|
||||
public void setState(GameStateType type) {
|
||||
currentState = states.get(type);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
package se.urmo.game.state;
|
||||
|
||||
public enum GameStateType {
|
||||
PLAYING,
|
||||
PLAYING, GAME_OVER,
|
||||
}
|
||||
|
||||
@ -22,7 +22,6 @@ import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class GhostManager {
|
||||
public static final int SPRITE_SHEET_ROWS = 10;
|
||||
public static final int MAX_SPRITE_FRAMES = 4;
|
||||
public static final int BLINKY_ANIMATION = 0;
|
||||
public static final int PINKY_ANIMATION = 2;
|
||||
@ -90,10 +89,12 @@ public class GhostManager {
|
||||
}
|
||||
|
||||
public void setFrightMode() {
|
||||
this.setMode(GhostMode.FRIGHTENED);
|
||||
setMode(GhostMode.FRIGHTENED);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
phaseIndex = 0;
|
||||
setMode(GhostMode.SCATTER);
|
||||
ghosts.forEach(Ghost::resetPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,6 +63,14 @@ public class PlayingState implements GameState {
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
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);
|
||||
@ -55,6 +78,45 @@ public class PlayingState implements GameState {
|
||||
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() {
|
||||
Point pacmanScreenPos = pacman.getPosition();
|
||||
@ -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);
|
||||
|
||||
9
src/main/java/se/urmo/game/state/RoundPhase.java
Normal file
9
src/main/java/se/urmo/game/state/RoundPhase.java
Normal file
@ -0,0 +1,9 @@
|
||||
package se.urmo.game.state;
|
||||
|
||||
public enum RoundPhase {
|
||||
READY, // "READY!" shown briefly before play starts
|
||||
PLAYING, // normal gameplay
|
||||
LEVEL_COMPLETE, // all dots eaten; freeze briefly then advance level
|
||||
LIFE_LOST, // Pac-Man hit; freeze briefly then reset positions
|
||||
GAME_OVER
|
||||
}
|
||||
Reference in New Issue
Block a user