Guide 5 — Last Delivery
Chris Acosta
What you're building
A food delivery robot crossing a wasteland from point A to point B. Monsters try to intercept you and steal the food. Top-down, Crossy Road–adjacent.
Yours is the second movement rig in the class — no gravity, no jumping. And it has one design decision baked in that's worth understanding before you build: the food is the resource, not your health.
Time: about two and a half hours.
1. Before you start
- Finish Guide 0.
- You'll want Guide B §B2 (managers) and §B3 (camera). You do not need §B1 — your robot isn't a platformer character.
- No extra packages, no new input actions.
2. Scripts you'll use
Movement (Tier 5)
TopDownMover · (optionally GridMover, see section 3)
Delivery (Tier 5)
DeliveryObjective · DeliveryPoint · DroppedCargo · LaneSpawner
Combat (Tier 2)
Team · Hurtbox · Hitbox · EnemyChase · EnemyPatrol
Core
Health · DamageOnContact · Checkpoint · RespawnManager · CameraTargetAssigner · SceneLoader · GameManager · AudioManager · HUDController
3. The design decision: what does failure mean?
Your pitch says monsters "try to intercept you to steal the food." That's a different game from "monsters hurt you," and the kit supports the first one directly.
DeliveryObjective treats cargo as the resource. A monster hit makes you drop a package into the world, which you can scramble back to recover before it despawns. Arrive at the customer with nothing and the delivery fails.
Why this is the better fit for your game:
- A delivery robot with a health bar is just an action game with a delivery skin.
- Dropping food creates a decision — go back for it under pressure, or cut your losses and deliver what's left.
- It gives you tension without needing combat, which suits a robot that can't fight.
You can have both. Wire Health.OnDamaged → DeliveryObjective.LoseOne and monsters both hurt you and cost you food. I'd build cargo-only first and see whether it needs more.
Movement mode
TopDownMover(recommended) — smooth 8-direction movement. Free and natural.GridMoverin Stepped mode — one cell per press, properly Crossy Road. More rigid, more puzzle-like.
This guide uses TopDownMover. If you want the grid feel, swap the component and read Guide 2 §3 for the settings.
4. Build the robot
- GameObject → Create Empty, name it
Robot. Tag →Player. - Sprite Renderer with your robot sprite.
- Add:
| Component | Settings |
|---|---|
| Rigidbody2D | Gravity Scale 0 · Freeze Rotation Z ✓ · Collision Detection Continuous |
| Capsule Collider 2D | fit the robot |
| Player Input | Behavior: Send Messages · Default Map Player |
| TopDownMover | see below |
| Health | Max Health 3 · Invulnerability Time 1 |
| DeliveryObjective | section 5 |
TopDownMover settings
| Field | Value | Note |
|---|---|---|
| Move Speed | 5 | |
| Acceleration | 50 | |
| Deceleration | 60 | |
| Normalize Diagonal | ✓ | stops diagonal movement being 40% faster |
| Facing | RotateSprite | a robot that turns to face its direction reads well |
| Rotation Offset | 0 | set to −90 if your art points up instead of right |
| AI Controlled | ✗ |
Facing modes:
RotateSpritesuits a vehicle or robot.FlipSpriteis simplest if your robot is symmetrical.FourDirectionneeds eight animation clips — good, but a lot of art. Start with RotateSprite.
-
Child
Hurtbox: trigger collider, Hurtbox component (Team = Player), object layerHurtbox. -
Child
CarriedFood: a small sprite of the package, positioned above the robot. This is what shows you're carrying something —DeliveryObjectiveshows and hides it.
5. Set up the cargo system
On Robot, fill in DeliveryObjective:
| Field | Value |
|---|---|
| Starting Cargo | 3 |
| Carried Visual | drag the CarriedFood child in |
| Dropped Cargo Prefab | your DroppedFood prefab (build it next) |
| Drop Force | 3 |
| Loss Cooldown | 1 |
| Lose Sfx | cargo_lost |
| Pickup Sfx | collect |
| Deliver Sfx | delivered |
Loss Cooldown 1 means one monster can't strip you of everything in a single collision. It's the difference between a tense moment and an instant loss.
Starting Cargo 3 gives the player room to lose one and keep going. Set it to 1 if you want a single precious package and a much harder game — that's a legitimate design choice, just a harsher one.
The dropped food prefab
- Empty GameObject
DroppedFood+ Sprite Renderer. - Rigidbody2D: Gravity Scale 0, Linear Damping 3 (so it slides and stops).
- Circle Collider 2D, Is Trigger ✓.
- DroppedCargo component:
| Field | Value |
|---|---|
| Despawn After | 8 |
| Blink Before Despawn | 3 |
| Pickup Delay | 0.4 |
- Save as a prefab and drag it into
DeliveryObjective's Dropped Cargo Prefab slot.
Despawn After 8 is your tension dial. Eight seconds is enough to turn around and grab it if you're quick. Drop it to 5 and recovery becomes a real risk.
6. Build the monsters
You want two kinds: predictable traffic and unpredictable hunters. The mix is what makes a route into a puzzle.
The hunter (chases you)
- Empty GameObject
Monster, Tag →Enemy, sprite. - Rigidbody2D (Gravity Scale 0, Freeze Rotation Z), Capsule Collider 2D.
- Health — Max Health 3 · Destroy On Death ✓ (they can't actually be killed in your game, but it prevents oddities)
- EnemyChase:
| Field | Value |
|---|---|
| Detect Radius | 6 |
| Lose Radius | 10 |
| Require Line Of Sight | ✗ (no walls in an open wasteland) |
| Movement | Free — no gravity, moves in all directions |
| Chase Speed | 3.5 — slower than you, so you can outrun them |
| Acceleration | 10 |
| Attack Range | 0.8 |
| Attack Cooldown | 2 |
| Stop In Range | ✗ |
- Child
Hurtbox: Team = Enemy, layerHurtbox. - Child
StealHitbox: trigger collider + Hitbox:
| Field | Value |
|---|---|
| Target Team | Player |
| Damage | 0 ← important |
| Knockback Force | 4 |
| Repeat Delay | 1.5 |
Damage 0 is the trick. The monster hits you, knocks you back, but doesn't hurt your health — it steals food instead. Wire that in section 9.
- Save as a prefab.
Chase Speed must be lower than your Move Speed. At 3.5 against your 5, a monster is a threat you can escape by running — which makes running a real option, and running while carrying something is your game.
The lane traffic
- Make a hazard prefab — a rolling barrel, a mutant, a wrecked truck. Sprite + Rigidbody2D (Gravity 0) + trigger collider +
DamageOnContact(Target TagPlayer, Damage 1, or Damage 0 if you want it to steal too). - Empty GameObject
Lane1at one edge of the play area. - Add LaneSpawner:
| Field | Value |
|---|---|
| Direction | (1, 0) for left-to-right |
| Lane Length | 24 (wide enough to cross the whole screen) |
| Prefabs | your hazard prefab |
| Max Alive | 4 |
| Start Delay | 0 |
| Interval | 2 |
| Interval Variance | 0.5 |
| Speed | 4 |
| Speed Variance | 1 |
| Face Direction | ✓ |
| Rotate Instead Of Flip | ✓ for vehicles, ✗ for creatures |
- Duplicate for more lanes. Stagger the Start Delay (0, 0.7, 1.4) so they don't all fire in sync — a wall of simultaneous hazards is unfair, a rhythm is a puzzle.
The orange gizmo arrow in the Scene view shows where a lane sends things. Use it.
7. Point B — the delivery point
- Empty GameObject
CustomerDoorat the end of your route, + sprite (a house, a hungry customer). - Box Collider 2D, Is Trigger ✓.
- DeliveryPoint:
| Field | Value |
|---|---|
| Required Cargo | 1 |
| Complete Level | ✓ |
| Set Flag On Delivery | (leave empty) |
Required Cargo 1 means arriving with anything at all counts as a success. Set it to 3 and you must arrive with everything — much harder, and it makes every dropped package a genuine crisis. Start at 1.
8. Camera, managers, HUD
Camera
Guide B §B3, with one change: for a top-down game set Damping X and Y both to 0.8 — even damping, since there's no "up" that matters more.
If your route is a long corridor, add the CinemachineConfiner2D and a bounds polygon.
Managers
GameManager, RespawnManager, AudioManager, SceneLoader. On RespawnManager, Use Lives ✗ — your fail state is losing the food, not running out of lives.
HUD
- Canvas → TMP text
CargoText, top-left. Text:Packages: 3. - Optionally a health bar or hearts.
- Empty child
HUDwith HUDController; drag your health display in.
The cargo count needs its own wiring since it doesn't come from CollectionTracker — see the next section.
9. Wire it up
| On this object | Event | Drag in | Choose |
|---|---|---|---|
Monster → StealHitbox Hitbox | On Hit | Robot | DeliveryObjective.LoseOne |
Robot → DeliveryObjective | On Cargo Changed | CargoText | TMP_Text.text — see note |
Robot → DeliveryObjective | On All Cargo Lost | GameManager | GameManager.GameOver |
Robot → DeliveryObjective | On Cargo Lost | AudioManager | PlaySFX (string) → cargo_lost |
CustomerDoor → DeliveryPoint | On Arrived Empty | GameManager | GameManager.GameOver |
Robot → Health | On Died | RespawnManager | RespawnManager.OnPlayerDied |
Robot → Health | On Health Changed | HUD | HUDController.UpdateHealth (Dynamic) |
Row 1 is the heart of your game. The monster's hitbox fires OnHit, which calls LoseOne on the robot. That's the theft.
Row 2 note: OnCargoChanged sends an int and TMP's text wants a string, so they don't connect directly. Two easy options:
- Simplest: skip this wiring and instead add an Item Counter — but cargo isn't an ItemType, so that won't work either.
- What I'd do: leave
CargoTextshowing a static label likePACKAGESand put the count on screen a different way — three small package icons that you disable one at a time viaOnCargoLost. Visual, no text formatting needed, and easier to read at a glance in a game where you're moving fast.
Ask your instructor if you'd rather have the number — it's a two-line helper script.
10. First playtest
Build a short open area with one hunter, one lane, and the customer door twenty units away.
- The robot moves in 8 directions and doesn't fall (Gravity Scale 0).
- Diagonals aren't faster — Normalize Diagonal ✓.
- The carried food shows above the robot, and vanishes when cargo hits 0.
- A monster notices you and chases, but you can outrun it.
- A monster hit drops a package into the world — you should see it appear and slide.
- You can pick the dropped package back up after a moment.
- The dropped package blinks and vanishes after 8 seconds.
- Losing all packages ends the game.
- Reaching the door with at least one package completes the level.
- Arriving empty fails rather than succeeding.
Step 5 is the one to check carefully — it's your whole design. If a monster hit does nothing, the OnHit → LoseOne wiring is missing or the hitbox teams are wrong.
11. Then add
- The route. Your systems are done; the game is the layout. Wide open stretches to run, pinch points where lanes force timing, safe pockets to breathe.
- More monster types — one faster than you but with a short detect radius, one slow with a huge radius.
Checkpoints if your route gets long.EnemyPatrolmonsters that walk fixed routes — predictable danger you can plan around.- A second delivery in the same level: two
DeliveryPoints, deliver to both. - Sound: an alarm when a monster notices you, a clatter when food drops, a chime on delivery.
12. Design notes for your game specifically
Predictable plus unpredictable is the recipe. Lane traffic you can time, hunters you have to react to. Either alone gets boring — traffic becomes a rhythm you memorise, hunters become a chase you just outrun. Together, the traffic constrains where you can dodge to, and that's the interesting problem.
The dropped package is the best thing in your design. It turns a hit from a punishment into a decision under time pressure: the food is on the ground, a monster is closing, and you have eight seconds. Tune Despawn After until that choice is genuinely hard.
Make the monsters slower than you. A monster you can't outrun isn't a threat, it's a timer. At 3.5 against your 5, escape is always possible but never free — especially when the escape route runs through traffic.
The wasteland is a character. Crossy Road works partly because the world is legible at a glance — you can see every lane and every gap. Keep your layout readable from the camera's view; a route the player can plan is more fun than one they discover by dying.
13. Common problems
| What you see | What's wrong |
|---|---|
| Robot falls off the screen | Gravity Scale isn't 0 |
| Diagonal movement is faster | Normalize Diagonal unticked |
| Robot spins constantly | Freeze Rotation Z unticked, or Facing is RotateSprite with the wrong Rotation Offset |
| Monster hit does nothing | OnHit → LoseOne not wired, or hitbox/hurtbox teams are the same, or layers wrong |
| Monster hit hurts health instead of stealing | Hitbox Damage isn't 0 |
| One monster takes all your cargo at once | Loss Cooldown is 0 — set it to 1 |
| Dropped food can't be picked up | Pickup Delay too long, or it's not on a trigger collider |
| Dropped food never disappears | Despawn After is 0 |
| Lane hazards don't appear | Prefabs list empty, or Max Alive is 0 |
| All lanes fire at once | Give each a different Start Delay |
| Hazards fly off in the wrong direction | Check the Direction vector and the gizmo arrow |
| Delivery point does nothing | Not a trigger, or the robot isn't tagged Player, or Required Cargo is higher than what you have |