Guide 1 — Conquer the Cutthroat Course

Nicholas Murley


What you're building

A single trap-filled obstacle course. No timer, three lives, and traps that get nastier as you go: saw blades, fire, an acid pit, spikes, crushers, and electricity along the ceiling that shocks you if you jump too high. When you burn through all three lives, a suitably undignified sound plays.

Your game uses no enemies, no collectibles, and no dialogue — which makes it the cleanest build in the class. Everything you need is the core kit plus hazards.

Heads up for everyone else: this guide builds the player prefab, respawn loop and camera that eleven other games use. If your guide says "build the player as in Guide 1," sections 3 and 4 are what it means.

Time: about two hours for a playable first course.


1. Before you start


2. Scripts you'll use

Core (Tier 1) — the eleven you can't skip
PlayerController2D · PlayerAnimatorBridge · Health · DamageOnContact · Checkpoint · RespawnManager · CameraTargetAssigner · SceneLoader · GameManager · AudioManager · HUDController · MovingPlatform · ParallaxBackground

Hazards (Tier 4) — your actual game
SpinningSaw · SpikeTrap · Crusher · CyclingHazard · ElectricZone · KillZone · LevelExit

You will not need: anything from Tiers 2, 3, 5, 6, 7 or 8. If you find yourself adding an enemy script, you've wandered off your own game.


3. Build the player

Follow Guide B §B1 exactly, then come back. Short version:

One change from the default: Max Health 1

Your traps kill instantly. There's no health bar in a course game — you touch a saw, you die, you go back to the checkpoint. Setting Max Health to 1 and using Instant Kill on your hazards makes that immediate and readable.


4. Build the level and camera

The floor

  1. GameObject → 2D Object → Tilemap → Rectangular (or just use stretched sprites while prototyping — you can replace them later).
  2. Select the Tilemap or your ground sprites and set Layer → Ground.
  3. Ground pieces need a Tilemap Collider 2D (or a Box Collider 2D on each sprite).

Prototype with grey boxes. Build the whole course out of plain rectangles first and get it feeling right. Art last. It's much easier to move a grey box than to redraw a background.

The camera

Guide B §B3 — 2D Cinemachine camera + CameraTargetAssigner. Since your course is one long level, add the CinemachineConfiner2D and a CameraBounds polygon so the camera stops at the ends.

The managers

Guide B §B2. You need: GameManager, RespawnManager, AudioManager, SceneLoader. You do not need CollectionTracker or ChoiceFlagManager.


5. Set up lives and respawning

This is the heart of your game, so it's worth doing carefully.

On RespawnManager

Field Value
Player leave empty — it finds the tag
Respawn Delay 1
Use Lives ✓ ticked
Starting Lives 3

Checkpoints

  1. GameObject → Create Empty, name it Checkpoint.
  2. Add a Box Collider 2D, tick Is Trigger, size it about two units wide and three tall.
  3. Add the Checkpoint component.
  4. Optional: add a Sprite Renderer (a flag, a lamp) and assign Inactive Sprite and Active Sprite so it visibly lights up.
  5. Save it as a prefab and place one at the start of each difficulty section.

Your first checkpoint is free — RespawnManager uses the player's starting position until you touch one.

How many checkpoints?

Your pitch says the course gets harder in sections. One checkpoint per section is the right instinct. Too few and a death costs five minutes; too many and there's no tension. Start with four or five and adjust after someone else plays it.


6. Build your hazards

Each one is a prefab you'll place many times. Build them all now, then decorate the course.

6a. Spike (the simplest — start here)

  1. Empty GameObject Spike, add a Sprite Renderer.
  2. Box Collider 2D, Is Trigger ✓.
  3. DamageOnContact with:
Field Value
Target Tag Player
Instant Kill ✓
Knockback Force 0
  1. Save as prefab.

That's a working hazard — no hazard script needed. This is the pattern for everything below: trigger collider + DamageOnContact + something that turns it on and off.

6b. Saw blade

Same as the spike, plus:

To make it patrol, add MovingPlatform on the same object with two waypoints, and set its Rider Tag to something unused like Untagged so it doesn't try to carry the player.

Waypoints: create two empty GameObjects, position them at each end of the travel, then drag them out of the saw in the Hierarchy so they don't move with it. Drag both into the Waypoints list.

6c. Fire jet (on and off on a timer)

  1. Empty GameObject FireJet + Sprite Renderer (or a Particle System).
  2. Trigger collider + DamageOnContact (Instant Kill ✓).
  3. CyclingHazard:
Field Value Note
Always On ✗
Start On ✗
On Time 1 how long the flame burns
Off Time 1.5 the safe window
Warning Time 0.3
Sprite drag the Sprite Renderer in hidden while off
Warning Renderer a small "sparks" sprite shown just before it fires

Start Delay is how you make a row of jets fire in sequence — give them 0, 0.4, 0.8, 1.2 and the player has to run the rhythm.

6d. Acid pit

Empty GameObject with a wide Box Collider 2D (Is Trigger ✓) and a KillZone component. That's it — no DamageOnContact needed, KillZone handles it and also tidies up anything else that falls in.

Put one of these under your whole course as a safety net, so falling off the bottom kills you instead of dropping you into the void forever.

6e. Pop-up spikes

Slightly fiddlier because it has a child.

  1. Empty GameObject SpikeTrap — this is the parent, and it sits where the spikes will be when extended.
  2. Right-click → Create Empty child, name it Spikes. Add a Sprite Renderer, a trigger Box Collider 2D, and DamageOnContact (Instant Kill ✓).
  3. Select the parent, add SpikeTrap:
Field Value
Mode Timed
Spikes drag the Spikes child in
Hidden Offset X 0, Y −0.6 (tune so they vanish into the floor)
Move Speed 12
Out Time 1.5
In Time 1.5
Warning Time 0.3
Shake Amount 0.05

The shake before they pop is the fairness. Don't remove it.

Triggered mode is the other good option: set Mode to Triggered, add a second empty child with a big trigger collider, and drag it into Trigger Zone. Now they spring when the player gets close.

6f. Crusher

  1. Empty GameObject Crusher at the top of the shaft.
  2. Child Head with the block sprite, a Box Collider 2D with Is Trigger ✓, and DamageOnContact (Instant Kill ✓).
  3. On the parent, Crusher:
Field Value
Head drag the child in
Auto Distance ✓
Ground Layer Ground
Wait At Top 1.5
Warning Time 0.4
Slam Speed 25
Hold At Bottom 0.6
Rise Speed 3

Auto Distance raycasts down and works out how far to fall, so you can drop the same prefab into shafts of different depths and it just fits.

The rise is slow on purpose — that's the window the player runs through.

6g. Ceiling electricity — your signature trap

Your pitch: "Jump too high and the electricity shocks you."

  1. Empty GameObject CeilingShock.
  2. Box Collider 2D, Is Trigger ✓, stretched wide and thin along the ceiling of that section.
  3. DamageOnContact (Instant Kill ✓).
  4. ElectricZone:
Field Value
Always On ✓
Stun Duration 0.5
Flicker ✓
Flicker Rate 20
Sprite your arc sprite, if you have one

Position it so a normal jump is safe and a jump from a raised platform isn't. Playtest this one specifically — it's the trap most likely to feel unfair, because the player can't always see how high they're about to go.


7. The finish line

  1. Empty GameObject LevelExit + trigger collider.
  2. LevelExit component:
Field Value
Requirement None
Destination Next In Build (or Stay Here while testing)
Delay 1
Complete Sfx level_complete
  1. File → Build Settings and add your scenes in order, or LoadNext has nothing to load.

8. The HUD

  1. GameObject → UI → Canvas.
  2. Right-click Canvas → UI → Text - TextMeshPro. Name it LivesText, put it top-left, type Lives: 3.
  3. Add an empty child of the Canvas called HUD with the HUDController component.
  4. Drag LivesText into Lives Text. Leave everything else empty — you don't need a health bar, a score, or item counters.

9. Wire it up

Four connections. Select the object in the On this object column, find the event, click +, drag in the target, choose the function.

On this object Event Drag in Choose
Player → Health On Died RespawnManager RespawnManager.OnPlayerDied
RespawnManager On Lives Changed HUD HUDController.UpdateLives (Dynamic)
RespawnManager On Game Over GameManager GameManager.GameOver
RespawnManager On Game Over AudioManager AudioManager.PlaySFX (string) → type funny_death

That last one is your funny death sound. It fires once, when the third life is gone — not on every death, which would get old fast.

If a function appears twice in the dropdown, once under Static Parameters and once under Dynamic, pick Dynamic for UpdateLives.


10. First playtest

Build a short test course — twenty seconds of running — with one of each hazard. Then press Play and check, in order:

  1. You can walk and jump. If not: is the Rigidbody2D there? Is GroundCheck assigned? Is Ground Layer ticked?
  2. You land on the floor rather than falling through. If not: does the ground have a collider and the Ground layer?
  3. A spike kills you and you reappear. If you die but never come back, the Health.OnDied → RespawnManager.OnPlayerDied wiring is missing.
  4. The lives counter goes 3 → 2 → 1. If it doesn't move, check the OnLivesChanged wiring and that you picked the Dynamic version.
  5. The third death triggers game over and your sound plays.
  6. A checkpoint changes where you respawn.
  7. The camera follows and stops at the level edges.

Get all seven working on a tiny course before you build the real one. Debugging a twenty-second level is far easier than debugging a five-minute one.


11. Then add

Once the loop works, in roughly this order:

  1. More hazards, arranged in difficulty sections — this is your actual game, and it's level design rather than setup.
  2. MovingPlatform for platforms that carry you between hazard sections.
  3. ParallaxBackground — a few sprite layers with Depth 0.2 / 0.5 / 0.8 gives you a sense of speed for almost no effort.
  4. An Animator for the player (Guide B §B6). Two states and one parameter is enough.
  5. Sound. Jump, land, death, and the big one at the end. Add clips to AudioManager's Named Sounds list.
  6. A second level — duplicate the scene, rearrange, add both to Build Settings.

12. Design notes for your game specifically

Every trap needs a tell. Every timed hazard in the kit has a Warning Time with a shake or a warning sprite. That isn't decoration — a trap the player couldn't have anticipated isn't difficulty, it's a coin flip. Your whole game is traps, so this matters more for you than for anyone else in the class.

Three lives with no timer is a strong choice. It means the player can stop and study a section. Lean into that — traps with visible rhythms that reward watching before moving are more interesting than traps that are just fast.

Escalate one variable at a time. Section one: spikes. Section two: spikes plus fire. Section three: those plus a crusher. If everything arrives at once, the player can't learn any of it.

The death sound is a real design element. It's the thing players will quote at each other. Make sure it plays clearly, and consider making it slightly too long — the comic beat is in the pause afterward.


13. Common problems

What you see What's wrong
Player falls through the floor Ground has no collider, or the collider is a trigger
Player never jumps GroundCheck not assigned, or positioned inside the body instead of at the feet
Player jumps infinitely GroundCheck overlapping the player's own collider — move it lower, or make sure Ground Layer only has Ground ticked
Retracted spikes still kill An outdated DamageOnContact. The package version is correct — if you edited it, re-import
Crusher falls forever Auto Distance unticked and Slam Distance too big, or Ground Layer not set
Fire never turns on Always On is ticked, or Start Delay is enormous
Nothing happens when you die The OnDied event isn't wired
Lives counter stuck at 3 OnLivesChanged wired to the static version — redo it and pick Dynamic
Ceiling shock hits you when standing The collider is too tall. Make it thinner and raise it
Camera shows outside the level No CinemachineConfiner2D, or no bounding shape assigned

14. Checklist