Guide 2 — Weenie(dog) Maze
Jax Keenan
What you're building
A dachshund navigates a maze eating treats. Every treat makes the dog longer. Run into your own body and it's over. Snake, but with a wiener dog and walls.
Yours is the smallest complete game in the class — twelve scripts, three prefabs — and it's the one that proves the kit isn't only for platformers. You'll finish the core loop faster than anyone, which means you have room to make the feel good rather than just functional.
Time: about ninety minutes to a playable game.
1. Before you start
- Finish Guide 0.
- No extra packages.
- You do not need Guide B's player prefab — your dog isn't a platformer character. Skip to section 3.
2. Scripts you'll use
Movement & snake
GridMover · SnakeBody · TreatSpawner · MazeLoader · WrapAround (optional)
Collectibles
ItemType · Collectible · CollectionTracker
Managers
GameManager · SceneLoader · AudioManager · HUDController
You will not need: PlayerController2D, Health, Checkpoint, RespawnManager, or anything with gravity. Your dog doesn't fall and doesn't take damage — hitting yourself ends the run outright.
3. Build the dog's head
The head is the only thing the player controls. The body follows it.
- GameObject → Create Empty, name it
DogHead. - Tag →
Player. - Add a Sprite Renderer with your dog's head sprite (a coloured square is fine to start).
- Add:
| Component | Settings |
|---|---|
| Rigidbody2D | Gravity Scale 0 · Body Type Kinematic · Freeze Rotation Z ✓ |
| Box Collider 2D | Is Trigger ✓ · size about 0.8 × 0.8 |
| Player Input | Actions → your input asset · Default Map Player · Behavior: Send Messages |
| GridMover | see below |
| SnakeBody | see section 5 |
GridMover settings — this is where the feel lives
| Field | Value | What it does |
|---|---|---|
| Mode | Continuous | keeps moving forever; input only changes direction. This is Snake |
| Cell Size | 1 | must match your maze grid |
| Step Time | 0.15 | seconds per cell. Lower = faster |
| Speed Up Per Step | 0.002 | each treat makes it slightly quicker |
| Min Step Time | 0.06 | the speed cap |
| Blocking Layers | Ground | your walls |
| Snap On Start | ✓ | |
| Prevent Reversal | ✓ | can't turn 180° into yourself |
| Flip Sprite | ✓ |
Step Time is your difficulty dial. 0.15 is brisk. Try 0.2 for a gentler game, 0.12 if you want it tense. Change one thing and play it — don't tune three numbers at once.
Speed Up Per Step is optional but it's what makes a Snake game build tension. At 0.002, a hundred steps shaves 0.2 seconds off — noticeable but not sudden.
Why Kinematic?
The dog doesn't need physics — GridMover moves it by hand, cell by cell. A Dynamic rigidbody would fight that.
4. Build the body segment and the treat
Body segment prefab
- Empty GameObject
BodySegment. - Sprite Renderer — a slightly different sprite from the head. (Your dog is long. This is the joke. Lean into it: a stretched middle section reads better than a repeated circle.)
- Box Collider 2D, Is Trigger ✓, about 0.8 × 0.8.
- Layer →
SnakeBody. - No script. The segments are moved by
SnakeBodyon the head. - Drag into
Assets/MyGame/Prefabs/.
Optionally make a TailSegment prefab too — same thing with a tail sprite. SnakeBody will keep it at the end automatically.
The treat
- Right-click in Project → Create → GAME1303 → Item Type. Name it
Treat.- Display Name:
Treat - Score Value:
10 - Pickup Sound: a crunch, if you have one
- Display Name:
- Empty GameObject
Treatin the scene. - Sprite Renderer with your treat sprite.
- Circle Collider 2D, Is Trigger ✓, radius ~0.4.
- Collectible component:
- Item Type → drag your
Treatasset in - Amount: 1
- Bob: ✓ (a gentle float makes it read as collectable)
- Item Type → drag your
- Drag into Prefabs.
5. Set up SnakeBody
Back on DogHead, fill in the SnakeBody component:
| Field | Value | Note |
|---|---|---|
| Body Segment Prefab | your BodySegment | |
| Tail Prefab | your TailSegment (or leave empty) | |
| Starting Length | 3 | traditional |
| Segments Per Grow | 1 | 2 if you want it to grow fast |
| Grace Segments | 1 | see below |
| Max Length | 0 | 0 = unlimited |
| Self Collision Kills | ✓ | this is your fail condition |
| Hit Tolerance | 0.5 |
Grace Segments — don't set this to 0
The segment immediately behind the head can't kill you. That sounds like cheating; it isn't. Without it, tight turns kill you in ways that feel like a bug rather than a mistake, because the head briefly overlaps the segment it just left.
If your playtesters say "that death wasn't fair," raise it to 2.
How it actually works
Worth understanding, because it's the clever part of your game: the head records the cell it leaves on every step. Segment 1 moves to where the head was, segment 2 to where segment 1 was, and so on down the line. It's a queue of positions, not a hundred little scripts — which is why it stays fast no matter how long the dog gets.
6. Build the maze
You have two options. Try the text one first — it's much faster to iterate on.
Option A: type the maze (recommended)
- Make a wall prefab: empty GameObject
Wall, Sprite Renderer, Box Collider 2D (solid, not a trigger), Layer →Ground. Size 1 × 1. - Empty GameObject in the scene called
Maze, at position (0, 0, 0). - Add MazeLoader:
| Field | Value |
|---|---|
| Layout Text | paste the maze below |
| Cell Size | 1 |
| Centre On This Object | ✓ |
| Wall Prefab | your Wall |
| Wall Char | # |
| Player Char | P |
| Move Player To Start | ✓ |
| Build On Start | ✓ |
- Paste this into Layout Text to start:
#####################
#...................#
#.###.#####.#####.#.#
#.#...#...#.....#.#.#
#.#.###.#.#####.#.#.#
#.......#.......#...#
#.#####.#####.#####.#
#.....#...P...#.....#
#.###.#.#####.#.###.#
#...................#
#####################
# is a wall, . is empty, P is where the dog starts. Any other letter can be mapped to a prefab in the Marker Prefabs list.
- Press Play. The maze builds itself.
This is why it's worth doing: changing your maze is now editing a block of text, not dragging forty wall tiles. You can redesign the whole layout in thirty seconds, or paste one in from a spreadsheet.
Option B: draw it with a Tilemap
GameObject → 2D Object → Tilemap → Rectangular, paint your walls, add a Tilemap Collider 2D, set the Layer to Ground. Works fine — just slower to change.
7. Set up the treat spawner
- Empty GameObject
TreatSpawnerat the centre of your maze. - Add a Box Collider 2D, Is Trigger ✓, sized to cover the whole play area.
- Add TreatSpawner:
| Field | Value |
|---|---|
| Treat Prefab | your Treat prefab |
| Max Active | 1 |
| Respawn Delay | 0 |
| Spawn Area | drag this object's own Box Collider 2D in |
| Snap To Grid | ✓ |
| Cell Size | 1 |
| Blocking Layers | Ground and SnakeBody |
| Min Distance From Player | 2 |
| Attempts | 40 |
Blocking Layers must include SnakeBody or treats will spawn underneath your own dog, which looks broken even though it technically works.
The win condition, free
When the spawner tries forty times and can't find an empty cell, it fires OnSpawnFailed. In Snake, that means the board is full — the player has won. Wire it to GameManager.LevelComplete and you have a victory state for zero extra work.
8. Camera and managers
Camera
Your whole maze fits on one screen, so you want a static camera — no Cinemachine needed.
- Select Main Camera.
- Set Projection → Orthographic.
- Set Size so the maze fits with a little margin. For the 21×11 maze above, try 6.5.
- Position it at (0, 0, −10).
That's it. Don't add CameraTargetAssigner — a camera that follows a snake is nauseating.
Managers
Empty GameObjects with one component each: GameManager, AudioManager, SceneLoader, CollectionTracker.
On CollectionTracker, leave Persist Across Scenes unticked — a single-scene game doesn't need it.
9. The HUD
- GameObject → UI → Canvas.
- Right-click Canvas → UI → Text - TextMeshPro. Name it
ScoreText, top-left. - Another one called
LengthText, below it. - Empty child of the Canvas called
HUDwith the HUDController component. - Drag
ScoreTextinto Score Text. Set Score Format toScore: {0}. - For the length, add an Item Counter entry: Item Type →
Treat, Text →LengthText, Format →Length: {0}.
Optionally add a GameOverPanel (a UI Panel with a Text and a Restart Button) and drag it into GameManager's Game Over Panel field. Wire the button's OnClick to GameManager.RestartLevel.
10. Wire it up
Five connections:
| On this object | Event | Drag in | Choose |
|---|---|---|---|
Treat prefab → Collectible | On Collected | DogHead | SnakeBody.Grow |
DogHead → SnakeBody | On Self Collision | GameManager | GameManager.GameOver |
DogHead → SnakeBody | On Self Collision | AudioManager | AudioManager.PlaySFX (string) → death |
DogHead → GridMover | On Blocked | GameManager | GameManager.GameOver |
TreatSpawner | On Spawn Failed | GameManager | GameManager.LevelComplete |
CollectionTracker | On Count Changed | HUD | HUDController.UpdateItemCount (Dynamic) |
A design decision in row 4
GridMover.OnBlocked fires when the dog hits a wall. You have two choices:
- Wire it to GameOver (above) — hitting a wall kills you. Classic Snake, higher tension.
- Leave it unwired — the dog just stops at the wall until you turn. Gentler, more forgiving, arguably better for a maze where walls are everywhere.
Your pitch says "navigate a maze without running into yourself" — which suggests walls stop you and only yourself kills you. I'd start unwired and see how it plays. It's one connection either way.
11. First playtest
- The dog moves on its own the moment you press Play. If it doesn't, check Mode = Continuous and that Step Time isn't 0.
- Arrow keys change direction. If not: is Player Input on the head with Behavior = Send Messages?
- It can't reverse into itself. Prevent Reversal ✓.
- Three body segments follow the head. If they pile up in one spot, check Body Segment Prefab is assigned.
- A treat appears somewhere valid — not in a wall, not under the dog.
- Eating a treat makes the dog longer and the counter goes up.
- Running into your own body ends the game. Grow to about eight segments and deliberately turn into yourself.
- Walls stop you (or kill you, depending on your choice in section 10).
If segments lag oddly behind the head, that's normal for the first step or two while the path queue fills.
12. Then add
- Sound. Crunch on eat, a yelp on death. Named Sounds on
AudioManager. - Animation. Your dog is a sausage that turns corners — even two frames of leg movement sells it. Guide B §B6, but you only need
Speed. - A second maze. Duplicate the scene, paste a different layout into
MazeLoader. Add both to Build Settings and wireGameManager.NextLevel. WrapAround— if you want open edges instead of walls on the outside. Add it toDogHead, set the area to your maze bounds.- Multiple treats at once. Raise Max Active to 3 for a busier board.
- A high score.
CollectionTracker.Scoreis already counting; save it with PlayerPrefs or ask your instructor aboutLevelProgress.
13. Design notes for your game specifically
Your maze design is your game design. With Snake, the walls decide everything: how much room the player has to escape their own tail, whether there are dead ends that become death traps as the dog grows, whether the centre is safer than the edges. Build three very different mazes and play them — you'll learn more in twenty minutes than from any amount of tuning numbers.
A maze changes Snake fundamentally. In classic Snake the danger is entirely self-inflicted and the space is open. Add walls and you get a route-planning game — the player has to think a few moves ahead about where the tail will be. That's a genuinely different and more interesting problem, and it's the reason your twist is a good one.
Watch out for the unwinnable state. Long dog plus narrow corridors equals no legal move. Some Snake games treat that as a fair loss; some avoid it with wider passages. Decide which you want, because your maze layout determines it.
The dachshund is doing real work. A long dog is funnier than a snake and it makes growth readable at a glance. Keep the proportions exaggerated.
14. Common problems
| What you see | What's wrong |
|---|---|
| Dog doesn't move at all | Mode is Stepped, not Continuous |
| Dog moves but input does nothing | Player Input missing, or Behavior isn't Send Messages |
| Presses get ignored during a turn | That's the queue working — one input is remembered per step. Turn earlier |
| Segments all sit on top of each other | Body Segment Prefab not assigned, or Starting Length is 0 |
| Dies instantly on the first turn | Grace Segments is 0. Set it to 1 |
| Treats spawn inside walls | Blocking Layers doesn't include Ground |
| Treats spawn under the dog | Blocking Layers doesn't include SnakeBody, or the segment prefab isn't on that layer |
| Dog passes straight through walls | Wall colliders are triggers, or walls aren't on Ground, or Blocking Layers isn't set on GridMover |
| Maze builds in the wrong place | Centre On This Object unticked, or the Maze object isn't at (0,0,0) |
| Maze doesn't build | Layout Text empty, or Wall Prefab not assigned |
| Dog moves half a cell off-grid | Cell Size doesn't match between GridMover, MazeLoader and TreatSpawner. All three must agree |