diff --git a/src/main/java/se/urmo/game/entities/Fruit.java b/src/main/java/se/urmo/game/entities/Fruit.java new file mode 100644 index 0000000..5f91f89 --- /dev/null +++ b/src/main/java/se/urmo/game/entities/Fruit.java @@ -0,0 +1,45 @@ +package se.urmo.game.entities; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import se.urmo.game.map.GameMap; +import se.urmo.game.state.FruitType; + +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; + +@Slf4j +public class Fruit { + private final Point position; + private final BufferedImage sprite; + @Getter + private final int score; + private final long spawnTime; + private final long lifetimeMs = 9000; // ~9 seconds + + public Fruit(FruitType type) { + this.position = new Point(GameMap.colToScreen(13), GameMap.rowToScreen(16)); ; + this.sprite = type.getSprite(); + this.score = type.getScore(); + this.spawnTime = System.currentTimeMillis(); + } + + public void draw(Graphics g) { + g.drawImage(sprite, position.x + GameMap.MAP_TILESIZE / 2, position.y, null); + } + + public boolean isExpired() { + return System.currentTimeMillis() - spawnTime > lifetimeMs; + } + + public boolean collidesWith(PacMan pacman) { + //return pacman.distanceTo(position) < GameMap.MAP_TILESIZE / 2.0; + + Rectangle pacmanBounds = pacman.getBounds(); + Rectangle fruitBounds = new Rectangle(position.x, position.y, sprite.getWidth(), sprite.getHeight()); + return pacmanBounds.intersects(fruitBounds); + } + +} diff --git a/src/main/java/se/urmo/game/entities/PacMan.java b/src/main/java/se/urmo/game/entities/PacMan.java index 1db9962..ff19be0 100644 --- a/src/main/java/se/urmo/game/entities/PacMan.java +++ b/src/main/java/se/urmo/game/entities/PacMan.java @@ -76,7 +76,7 @@ public class PacMan { position.y - PACMAN_OFFSET, PACMAN_SIZE, PACMAN_SIZE, null); - g.drawImage(COLLISION_BOX, position.x - COLLISION_BOX_OFFSET, position.y - COLLISION_BOX_OFFSET, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, null); + //g.drawImage(COLLISION_BOX, position.x - COLLISION_BOX_OFFSET, position.y - COLLISION_BOX_OFFSET, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, null); //g.setColor(Color.BLUE); //g.fillRect(position.x-1, position.y-1, 3, 3); } @@ -129,4 +129,8 @@ public class PacMan { public Image getLifeIcon() { return movmentImages[0][1]; } + + public Rectangle getBounds() { + return new Rectangle(position.x - COLLISION_BOX_OFFSET, position.y - COLLISION_BOX_OFFSET, COLLISION_BOX_SIZE, COLLISION_BOX_SIZE); + } } diff --git a/src/main/java/se/urmo/game/map/GameMap.java b/src/main/java/se/urmo/game/map/GameMap.java index e5da8f1..2b92d91 100644 --- a/src/main/java/se/urmo/game/map/GameMap.java +++ b/src/main/java/se/urmo/game/map/GameMap.java @@ -77,11 +77,6 @@ public class GameMap { } } -// private BufferedImage getSprite(int value) { -// TileType type = TileType.fromValue(value); -// return SpriteSheetManager.get(type.getSpriteSheet()).getSprite(type); -// } - public boolean isPassable(List list){ return list.stream().allMatch(p -> isPassable(p.x, p.y)); } @@ -188,6 +183,13 @@ public class GameMap { return (screenY - OFFSET_Y) / MAP_TILESIZE; } + public static int colToScreen(int col) { + return col * MAP_TILESIZE + OFFSET_X; + } + public static int rowToScreen(int row) { + return row * MAP_TILESIZE + OFFSET_Y; + } + public MapTile getTile(Point screenPos) { int r = screenToRow(screenPos); int c = screenToCol(screenPos); diff --git a/src/main/java/se/urmo/game/state/FruitManager.java b/src/main/java/se/urmo/game/state/FruitManager.java new file mode 100644 index 0000000..99e3c6d --- /dev/null +++ b/src/main/java/se/urmo/game/state/FruitManager.java @@ -0,0 +1,46 @@ +package se.urmo.game.state; + +import lombok.extern.slf4j.Slf4j; +import se.urmo.game.entities.Fruit; +import se.urmo.game.entities.PacMan; + +import java.awt.Graphics; + +@Slf4j +public class FruitManager { + private Fruit activeFruit; + private int dotsEaten = 0; + + public void dotEaten() { + dotsEaten++; + if (dotsEaten == 10 || dotsEaten == 170) { + spawnFruit(1); + } + } + + private void spawnFruit(int level) { + FruitType type = FruitType.forLevel(level); + + activeFruit = new Fruit(type); + } + + public void update(PacMan pacman, PlayingState playingState) { + if (activeFruit != null) { + if (activeFruit.isExpired()) { + activeFruit = null; + return; + } + + if (activeFruit.collidesWith(pacman)) { + playingState.setScore(activeFruit.getScore()); + activeFruit = null; + } + } + } + + public void draw(Graphics g) { + if (activeFruit != null) { + activeFruit.draw(g); + } + } +} diff --git a/src/main/java/se/urmo/game/state/FruitType.java b/src/main/java/se/urmo/game/state/FruitType.java new file mode 100644 index 0000000..b600b98 --- /dev/null +++ b/src/main/java/se/urmo/game/state/FruitType.java @@ -0,0 +1,29 @@ +package se.urmo.game.state; + +import lombok.Getter; +import se.urmo.game.graphics.SpriteLocation; +import se.urmo.game.graphics.SpriteSheetManager; + +import java.awt.image.BufferedImage; +import java.util.Arrays; + +@Getter +public enum FruitType { + CHERRY(1, SpriteSheetManager.get(SpriteLocation.ITEM).getSprite(0,0), 100); + + private final int level; + private final BufferedImage sprite; + private final int score; + + FruitType(int level, BufferedImage sprite, int score) { + this.level = level; + this.sprite = sprite; + this.score = score; + } + + public static FruitType forLevel(int i) { + return Arrays.stream(values()) + .filter(fruitType -> fruitType.level ==i) + .findFirst().orElse(null); + } +} diff --git a/src/main/java/se/urmo/game/state/GhostManager.java b/src/main/java/se/urmo/game/state/GhostManager.java index 9ed30bf..e1fa671 100644 --- a/src/main/java/se/urmo/game/state/GhostManager.java +++ b/src/main/java/se/urmo/game/state/GhostManager.java @@ -48,9 +48,9 @@ public class GhostManager { // Create ghosts with their strategies Ghost blinky = new Ghost(ghostCollisionChecker, new BlinkyStrategy(), new ScatterToTopRight(), BLINKY_ANIMATION); ghosts.add(blinky); - ghosts.add(new Ghost(ghostCollisionChecker, new PinkyStrategy(), new ScatterToTopLeft(), PINKY_ANIMATION)); - ghosts.add(new Ghost(ghostCollisionChecker,new InkyStrategy(blinky), new ScatterToBottomRight(), INKY_ANIMATION)); - ghosts.add(new Ghost(ghostCollisionChecker, new ClydeStrategy(), new ScatterToBottomLeft(), CLYDE_ANIMATION)); + // ghosts.add(new Ghost(ghostCollisionChecker, new PinkyStrategy(), new ScatterToTopLeft(), PINKY_ANIMATION)); + // ghosts.add(new Ghost(ghostCollisionChecker,new InkyStrategy(blinky), new ScatterToBottomRight(), INKY_ANIMATION)); + // ghosts.add(new Ghost(ghostCollisionChecker, new ClydeStrategy(), new ScatterToBottomLeft(), CLYDE_ANIMATION)); setMode(GhostMode.CHASE); } diff --git a/src/main/java/se/urmo/game/state/LevelManager.java b/src/main/java/se/urmo/game/state/LevelManager.java new file mode 100644 index 0000000..5d9f740 --- /dev/null +++ b/src/main/java/se/urmo/game/state/LevelManager.java @@ -0,0 +1,4 @@ +package se.urmo.game.state; + +public class LevelManager { +} diff --git a/src/main/java/se/urmo/game/state/PlayingState.java b/src/main/java/se/urmo/game/state/PlayingState.java index 331abf3..23049d6 100644 --- a/src/main/java/se/urmo/game/state/PlayingState.java +++ b/src/main/java/se/urmo/game/state/PlayingState.java @@ -23,6 +23,8 @@ public class PlayingState implements GameState { private final GameStateManager gameStateManager; private final GhostManager ghostManager; private final Font arcadeFont; + private final FruitManager fruitManager; + private final LevelManager levelManager; private PacMan pacman; @Getter private GameMap map; @@ -35,6 +37,8 @@ public class PlayingState implements GameState { this.map = new GameMap("maps/map1.csv"); this.pacman = new PacMan(game, new CollisionChecker(map)); this.ghostManager = new GhostManager(new GhostCollisionChecker(map)); + this.fruitManager = new FruitManager(); + this.levelManager = new LevelManager(); this.arcadeFont = loadArcadeFont(); } @@ -42,6 +46,7 @@ public class PlayingState implements GameState { public void update() { pacman.update(); ghostManager.update(pacman, map); + fruitManager.update(pacman, this); checkCollisions(); handleDots(); } @@ -54,6 +59,7 @@ public class PlayingState implements GameState { ghostManager.setFrightMode(); } if(wasRemoved){ + fruitManager.dotEaten(); score+=tile.getTileType().getScore(); } } @@ -63,6 +69,7 @@ public class PlayingState implements GameState { map.draw(g); pacman.draw(g); ghostManager.draw(g); + fruitManager.draw(g); drawUI(g); } @@ -129,4 +136,8 @@ public class PlayingState implements GameState { return new Font("Monospaced", Font.BOLD, 16); } } + + public void setScore(int score) { + this.score += score; + } }