Minimal Pac-Man-lite (Unity / C#)
The step-7 project in overview-arcade-classics-as-learning-projects and the capstone of the route. It is the first project with real AI, and it brings together the skills the canon reference (see source-classic-games-canon) lists for Pac-Man: tilemaps, simple pathfinding, finite state machines, and pickups.
Original project inspired by a recognisable pattern — not a clone.
Files
| Script | Responsibility | Key wiki concept |
|---|---|---|
MazeGrid.cs | Tile maze: walls, pellets, cell↔world, BFS distance | unity-tilemap, pathfinding-algorithms, csharp-collections |
GridMover.cs | Base: glides actors cell-to-cell, asks subclass which way | csharp-inheritance |
PacPlayer.cs | Buffered grid input; eats pellets on arrival | unity-input |
Ghost.cs | Scatter / Chase / Frightened FSM choosing a BFS target | ai-state-machine-pattern |
PacManGame.cs | Phase rhythm, power-pellet mode, score, lives, win/lose | unity-gamemanager-pattern |
ArcadeHud.cs (in ../shared/) | Shared on-screen HUD: a status line plus a timed centre message, drawn with TextMeshPro | ui-design, game-interface-types |
How the three step-7 ideas show up
- Tilemap.
MazeGridis a grid of walls and pellets withCellToWorld/IsWalkable. It is generated as a connected “pillar” maze so it is always solvable; the README below shows how to swap in a hand-authored layout or a real unity-tilemap. - Pathfinding.
MazeGrid.Distanceis a breadth-first search. A ghost looks at its walkable neighbours and steps toward the one with the best BFS distance to its target — simple, but genuine pathfinding. For bigger maps this is where A* on pathfinding-algorithms takes over. - Finite state machine.
Ghosthas three states. Each picks a different target (Chase → the player, Scatter → a home corner, Frightened → away from the player), while the movement code stays identical. That separation of “what do I want?” from “how do I move?” is the heart of ai-state-machine-pattern.
GridMover is shared by the player and the ghosts via csharp-inheritance:
the gliding-between-cells mechanism is written once, and only the per-cell
decision differs (read input vs run the FSM).
Scene setup (about 12 minutes)
- New 2D scene, Main Camera set to Orthographic (size ~4).
- Tile prefabs — four square sprites, each dragged into the Project window as
a prefab (delete the scene copies). No scripts or colliders needed:
Wall(solid colour),Pellet(small dot),PowerPellet(bigger dot).
- Player prefab: a sprite with the
PacPlayerscript. Make it a prefab. - Ghost prefab: a sprite with the
Ghostscript. Make it a prefab. - Maze: empty GameObject
Mazeat the origin, addMazeGrid, and assign the Wall / Pellet / Power Pellet prefabs. Width and height should be odd (defaults 15 × 11). - Game: empty GameObject
Game, addPacManGame, assign the Maze, the Player Prefab, and the Ghost Prefab. - HUD: copy
../shared/ArcadeHud.csinto the project as well. Add GameObject → UI → Text - TextMeshPro (click Import TMP Essentials the first time). Unity also creates a Canvas (leave it on Screen Space - Overlay) and an EventSystem. Name the textStatusTextand anchor it to the top-left; duplicate it asMessageText, anchor it to the centre, and set its alignment to centre. AddArcadeHudto the Canvas, drag both texts into its Status Text and Message Text fields, then drag the Canvas into the Hud field onGame. (Leave Hud empty and messages print to the Console instead.) - Press Play. WASD or arrows steer; eat all pellets to clear the level. A power pellet turns the ghosts blue (Frightened) so you can send them home for bonus points; otherwise a ghost costs a life. Score and lives show on screen.
The player and ghosts are spawned at the markers MazeGrid chooses, so you do not
place them in the scene yourself.
Why this is the capstone
Every earlier step fed into this one: grid movement (Snake), timed phases
(Space Invaders), state ownership (the game controllers), and now pathfinding and
a state machine driving an opponent that reacts to you. Tuning scatterTime,
chaseTime, frightenedTime, and the ghost speed changes the whole feel of the
hunt — see game-feel and smooth-learning-curves.
Extension ladder
- Four ghost personalities — give each ghost a different Chase target (ahead of the player, a mirror of another ghost, etc.) as the original does.
- A pathfinding* — swap the BFS for A* from pathfinding-algorithms and compare on a larger maze.
- Author the maze — feed
MazeGridastring[]layout (or a real unity-tilemap) instead of generating pillars, and parse#/./o/P/G. - Frightened polish — slow the ghosts and flash them near the end of the timer; classic game-feel cues.