diff --git a/src/main/java/se/urmo/game/map/GameMap.java b/src/main/java/se/urmo/game/map/GameMap.java index 9e79a32..ede1663 100644 --- a/src/main/java/se/urmo/game/map/GameMap.java +++ b/src/main/java/se/urmo/game/map/GameMap.java @@ -1,7 +1,6 @@ package se.urmo.game.map; import lombok.extern.slf4j.Slf4j; -import se.urmo.game.util.LoadSave; import java.awt.*; import java.awt.image.BufferedImage; @@ -16,14 +15,11 @@ 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[][] mapSpriteBuffer; private final MapTile[][] mapData; - private final BufferedImage[][] mapItemSpriteBuffer; - public GameMap() { - 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); + + public GameMap(String mapFilePath) { + this.mapData = loadMap(mapFilePath, MAP_ROW_SIZE, MAP_COL_SIZE); } private MapTile[][] loadMap(String path, int mapRowSize, int mapColSize) { @@ -64,69 +60,6 @@ public class GameMap { return data; } - private BufferedImage getSprite(int value) { - return switch (value){ - 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; - }; - } - public void draw(Graphics g) { for (int row = 0; row < mapData.length; row++) { for (int col = 0; col < mapData[row].length; col++) { @@ -141,6 +74,11 @@ 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)); } @@ -169,7 +107,7 @@ 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; } diff --git a/src/main/java/se/urmo/game/map/MapTile.java b/src/main/java/se/urmo/game/map/MapTile.java index e769faf..7cdde3d 100644 --- a/src/main/java/se/urmo/game/map/MapTile.java +++ b/src/main/java/se/urmo/game/map/MapTile.java @@ -16,7 +16,7 @@ public class MapTile { public MapTile(BufferedImage image, int value) { this.value = value; this.image = image; - this.solid = value != 0 && value != 99; + this.solid = value != 0 && value != 99 && value != 56; this.collisionMask = value != 0 ? createCollisionMask(image) : null; } diff --git a/src/main/java/se/urmo/game/map/SpriteLocation.java b/src/main/java/se/urmo/game/map/SpriteLocation.java new file mode 100644 index 0000000..a59eae3 --- /dev/null +++ b/src/main/java/se/urmo/game/map/SpriteLocation.java @@ -0,0 +1,32 @@ +package se.urmo.game.map; + +import lombok.Getter; +import se.urmo.game.util.LoadSave; + +import java.awt.image.BufferedImage; + +@Getter +public enum SpriteLocation { + MAP("sprites/PacMan-custom-spritemap-0-3.png", 5, 11), + ITEM("sprites/PacManAssets-Items.png", 2, 8), + NONE("", 0, 0) { // Special case for tiles without sprites + @Override + public BufferedImage[][] loadSprites(int tileSize) { + return new BufferedImage[][] {{ null }}; // Single null sprite + } + }; + + private final String path; + private final int rows; + private final int cols; + + SpriteLocation(String path, int rows, int cols) { + this.path = path; + this.rows = rows; + this.cols = cols; + } + + public BufferedImage[][] loadSprites(int tileSize) { + return LoadSave.loadSprites(path, rows, cols, tileSize); + } +} \ No newline at end of file diff --git a/src/main/java/se/urmo/game/map/SpriteSheet.java b/src/main/java/se/urmo/game/map/SpriteSheet.java new file mode 100644 index 0000000..3d1c71a --- /dev/null +++ b/src/main/java/se/urmo/game/map/SpriteSheet.java @@ -0,0 +1,34 @@ +package se.urmo.game.map; + +import lombok.Getter; +import java.awt.image.BufferedImage; + + +public class SpriteSheet { + private final BufferedImage[][] spriteSheet; + @Getter + private final SpriteLocation location; + + public SpriteSheet(SpriteLocation location) { + this.location = location; + this.spriteSheet = location.loadSprites(GameMap.MAP_TILESIZE); + } + + public BufferedImage getSprite(TileType tileType) { + if (tileType.getSpriteSheet() != location) { + throw new IllegalArgumentException("Tile type belongs to different sprite sheet"); + } + // NONE will always return null without additional checks + return getSprite(tileType.getRow(), tileType.getCol()); + } + + public BufferedImage getSprite(int row, int col) { + if (location == SpriteLocation.NONE) { + return null; + } + if (row >= spriteSheet.length || col >= spriteSheet[0].length) { + return null; + } + return spriteSheet[row][col]; + } +} \ No newline at end of file diff --git a/src/main/java/se/urmo/game/map/SpriteSheetManager.java b/src/main/java/se/urmo/game/map/SpriteSheetManager.java new file mode 100644 index 0000000..3586214 --- /dev/null +++ b/src/main/java/se/urmo/game/map/SpriteSheetManager.java @@ -0,0 +1,19 @@ +package se.urmo.game.map; + +import java.util.EnumMap; +import java.util.Map; + +public class SpriteSheetManager { + private static final Map spriteSheets = new EnumMap<>(SpriteLocation.class); + + public static SpriteSheet get(SpriteLocation location) { + return spriteSheets.computeIfAbsent(location, SpriteSheet::new); + } + + // Optionally add methods like: + public static void reloadAll() { + spriteSheets.clear(); + } +} + + diff --git a/src/main/java/se/urmo/game/map/TileType.java b/src/main/java/se/urmo/game/map/TileType.java new file mode 100644 index 0000000..9b7eec8 --- /dev/null +++ b/src/main/java/se/urmo/game/map/TileType.java @@ -0,0 +1,90 @@ +package se.urmo.game.map; + +import lombok.Getter; + +@Getter +public enum TileType { + SMALL_PELLET(0, false, SpriteLocation.ITEM, 1, 0), + TILE_1(1, true, SpriteLocation.MAP, 0, 0), + TILE_2(2, true, SpriteLocation.MAP, 0, 1), + TILE_3(3, true, SpriteLocation.MAP, 0, 2), + TILE_4(4, true, SpriteLocation.MAP, 0, 3), + TILE_5(5, true, SpriteLocation.MAP, 0, 4), + TILE_6(6, true, SpriteLocation.MAP, 0, 5), + TILE_7(7, true, SpriteLocation.MAP, 0, 6), + TILE_8(8, true, SpriteLocation.MAP, 0, 7), + TILE_9(9, true, SpriteLocation.MAP, 0, 8), + TILE_10(10, true, SpriteLocation.MAP, 0, 9), + TILE_11(11, true, SpriteLocation.MAP, 0, 10), + TILE_12(12, true, SpriteLocation.MAP, 1, 0), + TILE_13(13, true, SpriteLocation.MAP, 1, 1), + TILE_14(14, true, SpriteLocation.MAP, 1, 2), + TILE_15(15, true, SpriteLocation.MAP, 1, 3), + TILE_16(16, true, SpriteLocation.MAP, 1, 4), + TILE_17(17, true, SpriteLocation.MAP, 1, 5), + TILE_18(18, true, SpriteLocation.MAP, 1, 6), + TILE_19(19, true, SpriteLocation.MAP, 1, 7), + TILE_20(20, true, SpriteLocation.MAP, 1, 8), + TILE_21(21, true, SpriteLocation.MAP, 1, 9), + TILE_22(22, true, SpriteLocation.MAP, 1, 10), + TILE_23(23, true, SpriteLocation.MAP, 2, 0), + TILE_24(24, true, SpriteLocation.MAP, 2, 1), + TILE_25(25, true, SpriteLocation.MAP, 2, 2), + TILE_26(26, true, SpriteLocation.MAP, 2, 3), + TILE_27(27, true, SpriteLocation.MAP, 2, 4), + TILE_28(28, true, SpriteLocation.MAP, 2, 5), + TILE_29(29, true, SpriteLocation.MAP, 2, 6), + TILE_30(30, true, SpriteLocation.MAP, 2, 7), + TILE_31(31, true, SpriteLocation.MAP, 2, 8), + TILE_32(32, true, SpriteLocation.MAP, 2, 9), + TILE_33(33, true, SpriteLocation.MAP, 2, 10), + TILE_34(34, true, SpriteLocation.MAP, 3, 0), + TILE_35(35, true, SpriteLocation.MAP, 3, 1), + TILE_36(36, true, SpriteLocation.MAP, 3, 2), + TILE_37(37, true, SpriteLocation.MAP, 3, 3), + TILE_38(38, true, SpriteLocation.MAP, 3, 4), + TILE_39(39, true, SpriteLocation.MAP, 3, 5), + TILE_40(40, true, SpriteLocation.MAP, 3, 6), + TILE_41(41, true, SpriteLocation.MAP, 3, 7), + TILE_42(42, true, SpriteLocation.MAP, 3, 8), + TILE_43(43, true, SpriteLocation.MAP, 3, 9), + TILE_44(44, true, SpriteLocation.MAP, 3, 10), + TILE_45(45, true, SpriteLocation.MAP, 4, 0), + TILE_46(46, true, SpriteLocation.MAP, 4, 1), + TILE_47(47, true, SpriteLocation.MAP, 4, 2), + TILE_48(48, true, SpriteLocation.MAP, 4, 3), + TILE_49(49, true, SpriteLocation.MAP, 4, 4), + TILE_50(50, true, SpriteLocation.MAP, 4, 5), + TILE_51(51, true, SpriteLocation.MAP, 4, 6), + TILE_52(52, true, SpriteLocation.MAP, 4, 7), + TILE_53(53, true, SpriteLocation.MAP, 4, 8), + TILE_54(54, true, SpriteLocation.MAP, 4, 9), + TILE_55(55, true, SpriteLocation.MAP, 4, 10), + LARGE_PELLET(56, false, SpriteLocation.ITEM, 1, 1), + EMPTY(99, false, SpriteLocation.NONE, 0, 0); // No sprite associated with empty tiles + + private final int value; + private final boolean solid; + private final SpriteLocation spriteSheet; + private final int row; + private final int col; + + TileType(int value, boolean solid, SpriteLocation spriteSheet, int row, int col) { + this.value = value; + this.solid = solid; + this.spriteSheet = spriteSheet; + this.row = row; + this.col = col; + } + + public static TileType fromValue(int value) { + for (TileType type : values()) { + if (type.value == value) return type; + } + return EMPTY; + } + + public boolean hasSprite() { + return spriteSheet != null; + } +} \ No newline at end of file diff --git a/src/main/java/se/urmo/game/state/PlayingState.java b/src/main/java/se/urmo/game/state/PlayingState.java index 7d94e02..8c272c2 100644 --- a/src/main/java/se/urmo/game/state/PlayingState.java +++ b/src/main/java/se/urmo/game/state/PlayingState.java @@ -29,7 +29,7 @@ public class PlayingState implements GameState { public PlayingState(Game game, GameStateManager gameStateManager) { this.game = game; this.gameStateManager = gameStateManager; - this.map = new GameMap(); + this.map = new GameMap("maps/map1.csv"); this.pacman = new PacMan(game, new CollisionChecker(map)); this.ghostManager = new GhostManager(new GhostCollisionChecker(map)); this.arcadeFont = loadArcadeFont(); diff --git a/src/main/resources/maps/map1.csv b/src/main/resources/maps/map1.csv index be99ec7..b2584df 100644 --- a/src/main/resources/maps/map1.csv +++ b/src/main/resources/maps/map1.csv @@ -1,7 +1,7 @@ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,45,46, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15,17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,14 12, 0, 4, 5, 5, 6, 0, 4, 5, 5, 5, 6, 0,15,17, 0, 4, 5, 5, 5, 6, 0, 4, 5, 5, 6, 0,14 -12, 0,26,27,27,28, 0,26,27,27,27,28, 0,26,28, 0,26,27,27,27,28, 0,26,27,27,28, 0,14 +12,56,26,27,27,28, 0,26,27,27,27,28, 0,26,28, 0,26,27,27,27,28, 0,26,27,27,28,56,14 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,14 12, 0, 4, 5, 5, 6, 0, 4, 6, 0, 4, 5, 5, 5, 5, 5, 5, 6, 0, 4, 6, 0, 4, 5, 5, 6, 0,14 12, 0,26,27,27,28, 0,15,17, 0,26,27,27, 7, 8,27,27,28, 0,15,17, 0,26,27,27,28, 0,14