Skip to content

Commit f3592e9

Browse files
Fix issue with revival positions in 3D scene
1 parent 0c8d558 commit f3592e9

File tree

6 files changed

+72
-48
lines changed

6 files changed

+72
-48
lines changed

pacman-app-arcade-pacman/src/main/java/de/amr/pacmanfx/arcade/pacman/rendering/ArcadePacMan_GhostAnimationManager.java

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,26 @@ public ArcadePacMan_GhostAnimationManager(ArcadePacMan_SpriteSheet spriteSheet,
2929
@Override
3030
public SpriteAnimation createAnimation(String id) {
3131
return switch (id) {
32-
case ANIM_GHOST_NORMAL -> SpriteAnimation.build().of(ghostNormalSprites(Direction.LEFT)).frameTicks(8).forever();
33-
case ANIM_GHOST_FRIGHTENED -> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.GHOST_FRIGHTENED)).frameTicks(8).forever();
34-
case ANIM_GHOST_FLASHING -> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.GHOST_FLASHING)).frameTicks(7).forever();
35-
case ANIM_GHOST_EYES -> SpriteAnimation.build().of(ghostEyesSprites(Direction.LEFT)).once();
36-
case ANIM_GHOST_NUMBER -> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.GHOST_NUMBERS)).once();
37-
case ANIM_BLINKY_DAMAGED -> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.RED_GHOST_DAMAGED)).once();
38-
case ANIM_BLINKY_NAIL_DRESS_RAPTURE -> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.RED_GHOST_STRETCHED)).once();
39-
case ANIM_BLINKY_PATCHED -> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.RED_GHOST_PATCHED)).frameTicks(4).forever();
40-
case ANIM_BLINKY_NAKED -> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.RED_GHOST_NAKED)).frameTicks(4).forever();
41-
default -> throw new IllegalArgumentException("Illegal animation ID: " + id);
32+
case ANIM_GHOST_NORMAL
33+
-> SpriteAnimation.build().of(ghostNormalSprites(Direction.LEFT)).frameTicks(8).forever();
34+
case ANIM_GHOST_FRIGHTENED
35+
-> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.GHOST_FRIGHTENED)).frameTicks(8).forever();
36+
case ANIM_GHOST_FLASHING
37+
-> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.GHOST_FLASHING)).frameTicks(7).forever();
38+
case ANIM_GHOST_EYES
39+
-> SpriteAnimation.build().of(ghostEyesSprites(Direction.LEFT)).once();
40+
case ANIM_GHOST_NUMBER
41+
-> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.GHOST_NUMBERS)).once();
42+
case ANIM_BLINKY_DAMAGED
43+
-> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.RED_GHOST_DAMAGED)).once();
44+
case ANIM_BLINKY_NAIL_DRESS_RAPTURE
45+
-> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.RED_GHOST_STRETCHED)).once();
46+
case ANIM_BLINKY_PATCHED
47+
-> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.RED_GHOST_PATCHED)).frameTicks(4).forever();
48+
case ANIM_BLINKY_NAKED
49+
-> SpriteAnimation.build().of(spriteSheet().content().spriteSequence(SpriteID.RED_GHOST_NAKED)).frameTicks(4).forever();
50+
default
51+
-> throw new IllegalArgumentException("Illegal animation ID: " + id);
4252
};
4353
}
4454

pacman-app-arcade-pacman/src/main/java/de/amr/pacmanfx/arcade/pacman/rendering/ArcadePacMan_SpriteSheet.java

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ public record ArcadePacMan_SpriteSheet(Image sourceImage) implements SpriteSheet
1919
private static final int R16 = 16; // 16x16 squares in sprite sheet
2020
private static final int OFF_X = 456; // right from here the sprites are located
2121

22-
private static RectShort[] harvestSpritesAt(int tileX, int tileY, int spriteCount) {
22+
private static RectShort[] clipSpritesAt(int tileX, int tileY, int spriteCount) {
2323
return IntStream.range(tileX, tileX + spriteCount)
24-
.mapToObj(tx -> harvestSpriteAt(tx, tileY))
24+
.mapToObj(tx -> clipSpriteAt(tx, tileY))
2525
.toArray(RectShort[]::new);
2626
}
2727

28-
private static RectShort harvestSpriteAt(int tileX, int tileY) {
28+
private static RectShort clipSpriteAt(int tileX, int tileY) {
2929
return rect(OFF_X + R16 * tileX, R16 * tileY, R16, R16);
3030
}
3131

@@ -59,45 +59,45 @@ private static RectShort harvestSpriteAt(int tileX, int tileY) {
5959
SPRITE_MAP.addSpriteSequence(SpriteID.PACMAN_MUNCHING_UP, makePacManMunchingSpriteSeq(2));
6060
SPRITE_MAP.addSpriteSequence(SpriteID.PACMAN_MUNCHING_DOWN, makePacManMunchingSpriteSeq(3));
6161
SPRITE_MAP.addSpriteSequence(SpriteID.PACMAN_DYING, makePacManDyingSpriteSeq());
62-
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_RIGHT, harvestSpritesAt(0, 4, 2));
63-
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_LEFT, harvestSpritesAt(2, 4, 2));
64-
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_UP, harvestSpritesAt(4, 4, 2));
65-
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_DOWN, harvestSpritesAt(6, 4, 2));
66-
SPRITE_MAP.addSpriteSequence(SpriteID.PINK_GHOST_RIGHT, harvestSpritesAt(0, 5, 2));
67-
SPRITE_MAP.addSpriteSequence(SpriteID.PINK_GHOST_LEFT, harvestSpritesAt(2, 5, 2));
68-
SPRITE_MAP.addSpriteSequence(SpriteID.PINK_GHOST_UP, harvestSpritesAt(4, 5, 2));
69-
SPRITE_MAP.addSpriteSequence(SpriteID.PINK_GHOST_DOWN, harvestSpritesAt(6, 5, 2));
70-
SPRITE_MAP.addSpriteSequence(SpriteID.CYAN_GHOST_RIGHT, harvestSpritesAt(0, 6, 2));
71-
SPRITE_MAP.addSpriteSequence(SpriteID.CYAN_GHOST_LEFT, harvestSpritesAt(2, 6, 2));
72-
SPRITE_MAP.addSpriteSequence(SpriteID.CYAN_GHOST_UP, harvestSpritesAt(4, 6, 2));
73-
SPRITE_MAP.addSpriteSequence(SpriteID.CYAN_GHOST_DOWN, harvestSpritesAt(6, 6, 2));
74-
SPRITE_MAP.addSpriteSequence(SpriteID.ORANGE_GHOST_RIGHT, harvestSpritesAt(0, 7, 2));
75-
SPRITE_MAP.addSpriteSequence(SpriteID.ORANGE_GHOST_LEFT, harvestSpritesAt(2, 7, 2));
76-
SPRITE_MAP.addSpriteSequence(SpriteID.ORANGE_GHOST_UP, harvestSpritesAt(4, 7, 2));
77-
SPRITE_MAP.addSpriteSequence(SpriteID.ORANGE_GHOST_DOWN, harvestSpritesAt(6, 7, 2));
62+
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_RIGHT, clipSpritesAt(0, 4, 2));
63+
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_LEFT, clipSpritesAt(2, 4, 2));
64+
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_UP, clipSpritesAt(4, 4, 2));
65+
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_DOWN, clipSpritesAt(6, 4, 2));
66+
SPRITE_MAP.addSpriteSequence(SpriteID.PINK_GHOST_RIGHT, clipSpritesAt(0, 5, 2));
67+
SPRITE_MAP.addSpriteSequence(SpriteID.PINK_GHOST_LEFT, clipSpritesAt(2, 5, 2));
68+
SPRITE_MAP.addSpriteSequence(SpriteID.PINK_GHOST_UP, clipSpritesAt(4, 5, 2));
69+
SPRITE_MAP.addSpriteSequence(SpriteID.PINK_GHOST_DOWN, clipSpritesAt(6, 5, 2));
70+
SPRITE_MAP.addSpriteSequence(SpriteID.CYAN_GHOST_RIGHT, clipSpritesAt(0, 6, 2));
71+
SPRITE_MAP.addSpriteSequence(SpriteID.CYAN_GHOST_LEFT, clipSpritesAt(2, 6, 2));
72+
SPRITE_MAP.addSpriteSequence(SpriteID.CYAN_GHOST_UP, clipSpritesAt(4, 6, 2));
73+
SPRITE_MAP.addSpriteSequence(SpriteID.CYAN_GHOST_DOWN, clipSpritesAt(6, 6, 2));
74+
SPRITE_MAP.addSpriteSequence(SpriteID.ORANGE_GHOST_RIGHT, clipSpritesAt(0, 7, 2));
75+
SPRITE_MAP.addSpriteSequence(SpriteID.ORANGE_GHOST_LEFT, clipSpritesAt(2, 7, 2));
76+
SPRITE_MAP.addSpriteSequence(SpriteID.ORANGE_GHOST_UP, clipSpritesAt(4, 7, 2));
77+
SPRITE_MAP.addSpriteSequence(SpriteID.ORANGE_GHOST_DOWN, clipSpritesAt(6, 7, 2));
7878
SPRITE_MAP.addSpriteSequence(SpriteID.GALLERY_GHOSTS,
79-
harvestSpriteAt(0, 4),
80-
harvestSpriteAt(0, 5),
81-
harvestSpriteAt(0, 6),
82-
harvestSpriteAt(0, 7)
79+
clipSpriteAt(0, 4),
80+
clipSpriteAt(0, 5),
81+
clipSpriteAt(0, 6),
82+
clipSpriteAt(0, 7)
8383
);
84-
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_FRIGHTENED, harvestSpritesAt(8, 4, 2));
85-
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_FLASHING, harvestSpritesAt(8, 4, 4));
86-
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_EYES_RIGHT, harvestSpritesAt(8, 5, 1));
87-
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_EYES_LEFT, harvestSpritesAt(9, 5, 1));
88-
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_EYES_UP, harvestSpritesAt(10, 5, 1));
89-
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_EYES_DOWN, harvestSpritesAt(11, 5, 1));
84+
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_FRIGHTENED, clipSpritesAt(8, 4, 2));
85+
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_FLASHING, clipSpritesAt(8, 4, 4));
86+
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_EYES_RIGHT, clipSpritesAt(8, 5, 1));
87+
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_EYES_LEFT, clipSpritesAt(9, 5, 1));
88+
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_EYES_UP, clipSpritesAt(10, 5, 1));
89+
SPRITE_MAP.addSpriteSequence(SpriteID.GHOST_EYES_DOWN, clipSpritesAt(11, 5, 1));
9090
SPRITE_MAP.addSpriteSequence(SpriteID.PACMAN_BIG,
9191
rect(OFF_X + 32, 16, 32, 32),
9292
rect(OFF_X + 64, 16, 32, 32),
9393
rect(OFF_X + 96, 16, 32, 32)
9494
);
95-
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_STRETCHED, harvestSpritesAt(8, 6, 5));
95+
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_STRETCHED, clipSpritesAt(8, 6, 5));
9696
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_DAMAGED,
9797
rect(OFF_X + R16 * 8 + 1, R16 * 7 + 1, 14, 14),
9898
rect(OFF_X + R16 * 9 + 1, R16 * 7 + 1, 14, 14)
9999
);
100-
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_PATCHED, harvestSpritesAt(10, 7, 2));
100+
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_PATCHED, clipSpritesAt(10, 7, 2));
101101
SPRITE_MAP.addSpriteSequence(SpriteID.RED_GHOST_NAKED,
102102
rect(OFF_X + R16 * 8, R16 * 8, R16 * 2, R16),
103103
rect(OFF_X + R16 * 10, R16 * 8, R16 * 2, R16)

pacman-core/src/main/java/de/amr/pacmanfx/model/GameLevel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ public void setGhosts(Ghost... ghosts) {
263263
for (Ghost ghost : ghosts) {
264264
byte personality = ghost.id().personality();
265265
Vector2i tile = switch (personality) {
266-
case RED_GHOST_SHADOW, PINK_GHOST_SPEEDY -> worldMap.getTerrainTileProperty(POS_RED_GHOST);
266+
case RED_GHOST_SHADOW, PINK_GHOST_SPEEDY -> worldMap.getTerrainTileProperty(POS_PINK_GHOST);
267267
case CYAN_GHOST_BASHFUL -> worldMap.getTerrainTileProperty(POS_CYAN_GHOST);
268268
case ORANGE_GHOST_POKEY -> worldMap.getTerrainTileProperty(POS_ORANGE_GHOST);
269269
default -> throw new IllegalArgumentException("Illegal ghost personality: %d".formatted(personality));

pacman-ui-lib/src/main/java/de/amr/pacmanfx/uilib/animation/EnergizerExplosionAndRecycling.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ else if (particle.center().getZ() > 50) {
165165
particles.removeAll(trash);
166166
particlesGroup.getChildren().removeAll(trash);
167167
trash.forEach(Particle::dispose);
168-
Logger.info("{} particles disposed, t={}", trash.size(), t);
168+
Logger.debug("{} particles disposed, t={}", trash.size(), t);
169169
trash.clear();
170170
});
171171
}

pacman-ui-lib/src/main/java/de/amr/pacmanfx/uilib/assets/SpriteMap.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
Copyright (c) 2021-2025 Armin Reichert (MIT License)
3+
See file LICENSE in repository root directory for details.
4+
*/
15
package de.amr.pacmanfx.uilib.assets;
26

37
import de.amr.pacmanfx.lib.RectShort;

pacman-ui/src/main/java/de/amr/pacmanfx/ui/_3d/GameLevel3D.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,10 @@ private void createMaze3D() {
526526
house.ghostRevivalTile(gameLevel.ghost(PINK_GHOST_SPEEDY).id()),
527527
house.ghostRevivalTile(gameLevel.ghost(ORANGE_GHOST_POKEY).id()),
528528
};
529+
// Note: revival tile is the left of the pair of tiles in the house where the ghost is placed. The center
530+
// of the 3D shape is one tile to the right and a half tile to the bottom from the tile origin.
529531
Vector2f[] ghostRevivalPositions = Stream.of(ghostRevivalTiles)
530-
.map(tile -> tile.scaled((float) TS).plus(HTS, HTS))
532+
.map(tile -> tile.scaled((float) TS).plus(TS, HTS))
531533
.toArray(Vector2f[]::new);
532534

533535
house3D = new ArcadeHouse3D(
@@ -623,20 +625,28 @@ private void createEnergizers3D() {
623625
House house = gameLevel.house().orElseThrow();
624626
Vector2i[] ghostRevivalTiles = {
625627
house.ghostRevivalTile(gameLevel.ghost(RED_GHOST_SHADOW).id()),
626-
house.ghostRevivalTile(gameLevel.ghost(CYAN_GHOST_BASHFUL).id()),
627628
house.ghostRevivalTile(gameLevel.ghost(PINK_GHOST_SPEEDY).id()),
629+
house.ghostRevivalTile(gameLevel.ghost(CYAN_GHOST_BASHFUL).id()),
628630
house.ghostRevivalTile(gameLevel.ghost(ORANGE_GHOST_POKEY).id()),
629631
};
630-
Vector2f[] ghostRevivalCenters = Stream.of(ghostRevivalTiles)
631-
.map(tile -> tile.scaled((float) TS).plus(TS, HTS))
632-
.toArray(Vector2f[]::new);
632+
633+
Vector2f[] ghostRevivalCenters = {
634+
revivalPositionCenter(ghostRevivalTiles[RED_GHOST_SHADOW]),
635+
revivalPositionCenter(ghostRevivalTiles[PINK_GHOST_SPEEDY]),
636+
revivalPositionCenter(ghostRevivalTiles[CYAN_GHOST_BASHFUL]),
637+
revivalPositionCenter(ghostRevivalTiles[ORANGE_GHOST_POKEY])
638+
};
633639

634640
energizers3D = gameLevel.tilesContainingFood()
635641
.filter(gameLevel::isEnergizerPosition)
636642
.map(tile -> createEnergizer3D(tile, radius, minScaling, maxScaling, ghostDressMaterials, ghostRevivalCenters))
637643
.collect(Collectors.toCollection(HashSet::new));
638644
}
639645

646+
private Vector2f revivalPositionCenter(Vector2i revivalTile) {
647+
return revivalTile.scaled(8f).plus(TS, HTS);
648+
}
649+
640650
private Energizer3D createEnergizer3D(
641651
Vector2i tile,
642652
float energizerRadius,

0 commit comments

Comments
 (0)