Guide 15 — Apep's Trial

Lazaro Garcia


What you're building

Ra's barque is delayed for construction and the world ends if nobody makes his nightly journey. You're a magic construct standing in for Ra, travelling to stop Apep and bring light to the new day.

The core mechanic: the camera switches from first-person 3D to a 2D side-scroller or top-down view, and the controls change with it. You have dash, air dash, double jump, glide, sprint.

Yours is the only hybrid build in the class, and the most conceptually ambitious. It's also the one with the clearest single piece of advice:

Prototype the switch on grey boxes before you make any art or level.

The mechanic either feels good or it doesn't, and you want to know that in week two rather than week ten. Everything else in your game depends on it.

Time: two hours for a working prototype. Do that first.


1. Before you start


2. Scripts you'll use

Mode switching (Tier 8)
CameraModeSwitcher · ModeSwitchTrigger

Controllers
PlayerController2D (2D side) · TopDownMover (top-down) · FirstPersonController (3D)

Movement (Tier 3)
Dash · DoubleJump · Glide · Sprint

Core
Health · DamageOnContact · Checkpoint · RespawnManager · SceneLoader · GameManager · AudioManager · HUDController · MovingPlatform

Puzzles (Tier 6)
PushBlock · PuzzleSwitch (Tier 4) · Door


3. Build the prototype first

Before art, before level design, before the barque. One scene, grey boxes, twenty minutes of testing.

The player object — this will look alarming

Your player carries both a CharacterController and a Rigidbody2D, plus all three movement scripts. Only one is ever enabled at a time, so they never fight — but the Inspector looks wrong. It isn't.

  1. GameObject → Create Empty, name it Player. Tag → Player.
  2. Add a Capsule as a child (GameObject → 3D Object → Capsule) for the 3D body, and a Sprite Renderer child for the 2D body. You'll show and hide these later; for the prototype, just the capsule is fine.
  3. Add to the root:
Component Settings
CharacterController Height 1.8 · Radius 0.3 · Center Y 0.9
Rigidbody2D Gravity Scale 3 · Freeze Rotation Z ✓
Capsule Collider 2D fit the sprite
Player Input Behavior: Send Messages
FirstPersonController Walk Speed 3.5 · Sprint 6
PlayerController2D Move Speed 8 · Jump Force 14
TopDownMover Move Speed 5
Health Max Health 3
  1. Child CameraHolder at Y 1.6 — drag it into FirstPersonController's Camera Pivot.
  2. Child GroundCheck at the feet — drag into PlayerController2D.
  3. Disable PlayerController2D and TopDownMover in the Inspector (untick their checkboxes). CameraModeSwitcher manages them from here.

The three cameras

  1. GameObject → Cinemachine → Cinemachine Camera ×3. Name them Cam3D, CamSide, CamTopDown.
  2. Cam3D — put it inside CameraHolder, position (0,0,0), rotation zero. Set its Follow and Look At empty.
  3. CamSide — add a Position Composer, set Follow to Player, and position it looking down −Z with the settings from Guide B §B3.
  4. CamTopDown — add a Position Composer, Follow = Player, rotate it to look straight down (rotation X = 90).
  5. Make sure Main Camera has a CinemachineBrain. Set Default Blend → Ease In Out, 0.6s.

The switcher

On Player, add CameraModeSwitcher:

Field Drag in
Camera 3D / Camera Side / Camera Top Down the three cameras
Active Priority 20
Inactive Priority 5
Controller 3D the FirstPersonController
Controller Side the PlayerController2D
Controller Top Down the TopDownMover
Character Controller the CharacterController
Body 2D the Rigidbody2D
Starting Mode FirstPerson3D
Blend Time 0.6 — match your Cinemachine default blend
Lock Input During Blend ✓
Manage Bodies ✓
Switch Sfx mode_switch

Test it with a button

Add a temporary UI Button wired to CameraModeSwitcher.SetModeByIndex with the parameter 1 (0 = 3D, 1 = side, 2 = top-down). Add two more for 0 and 2.

Press Play and click between them. You should see the camera blend, and the controls change with it. If that works and feels good, you have a game. If it feels bad, now is the cheapest possible moment to find out.


4. Doorway triggers

Once the button test works, replace it with real transitions.

  1. Empty GameObject Doorway with a 3D BoxCollider, Is Trigger ✓, at the threshold.
  2. Add ModeSwitchTrigger:
Field Value
Switcher leave empty — it finds it
Mode On Enter SideScroll2D
Restore On Exit ✓ for a two-way doorway
Mode On Exit FirstPerson3D
Reposition Player To see below
Snap Z Only ✓

The reposition point — do not skip this

Create an empty GameObject sitting exactly on the plane your 2D section runs along, and drag it into Reposition Player To. With Snap Z Only ticked, entering the doorway snaps the player onto that Z plane while leaving X and Y alone.

This is the single most common bug in a 3D/2D hybrid. Without it, the player enters 2D mode standing slightly off the plane, walks "into the background," and appears to phase through the level. It looks like a physics bug and it isn't.


5. Build the 2D sections

Once switching works, the 2D parts are ordinary platforming.

Add the movement abilities

On Player, add these — they only apply while PlayerController2D is the active controller:

Component Settings
Dash Speed 22 · Duration 0.15 · Cooldown 0.4 · Air Dashes 1 · Invulnerable ✓
DoubleJump Extra Jumps 1 · Air Jump Force 12
Glide Glide Fall Speed 2 · Min Fall Speed To Start 1 · Glide Move Multiplier 1.1
Sprint Sprint Multiplier 1.6 · Toggle Mode ✗

All four are in your pitch. They coexist without configuration — the Jump button is shared and they negotiate who acts.

Add the Dash input action to your input asset (Guide 0 §6).


6. Build the top-down sections

Top-down works the same way — same object, different active controller.

CameraModeSwitcher sets Rigidbody2D.gravityScale to 0 in top-down mode and 3 in side-scroll mode automatically — you don't manage that.

Puzzles suit top-down

Your pitch mentions the barque journey. Top-down sections are a natural fit for PushBlock and PuzzleSwitch puzzles — moving weights onto pressure plates reads much better from above than from the side.

PushBlock: sprite + Rigidbody2D + solid collider + the component (Mode Physics). Wire RespawnManager.OnRespawned → PushBlock.ResetPosition so a death can't make a puzzle unsolvable.


7. Show the right body

Your player has a 3D capsule and a 2D sprite. Show one at a time.

Wire CameraModeSwitcher.OnModeChanged… except it sends a Mode enum, which doesn't connect directly to SetActive.

The no-script version: use OnSwitchStarted and OnSwitchFinished plus separate ModeSwitchTrigger.OnEntered events on each doorway to toggle the two body objects. Slightly manual but it works.

The better version: ask your instructor for a three-line script that listens to OnModeChanged and enables the right body. It's genuinely three lines, and you'll want it.

For the prototype, just leave the capsule visible in all modes. It looks odd and it doesn't matter yet.


8. Managers and HUD

Guide B §B2 — GameManager, RespawnManager, AudioManager, SceneLoader.

HUD: a Canvas with hearts or a health bar, plus an empty HUD with HUDController.

Cursor handling: FirstPersonController locks the mouse in 3D mode and CameraModeSwitcher unlocks it when you leave. Escape releases it — useful in the editor. If you add a pause menu, wire it to FirstPersonController.UnlockCursor.


9. Wire it up

On this object Event Drag in Choose
Player → Health On Died RespawnManager RespawnManager.OnPlayerDied
Player → Health On Health Changed HUD HUDController.UpdateHealth (Dynamic)
RespawnManager On Respawned PushBlock PushBlock.ResetPosition
CameraModeSwitcher On Switch Started AudioManager PlaySFX (string) → mode_switch
PuzzleSwitch On Activated Door Door.Open
Player → Dash On Dash Started AudioManager PlaySFX (string) → dash

10. Prototype playtest

Do this before building any level.

  1. All three modes are reachable via your test buttons.
  2. The camera blends smoothly rather than snapping.
  3. Controls change with the mode — WASD+mouse in 3D, left/right+jump in side, 8-way in top-down.
  4. You can't move mid-blend (Lock Input During Blend ✓).
  5. A doorway trigger switches mode and repositions you onto the plane.
  6. You don't drift off the 2D plane — walk back and forth in side-scroll mode and confirm you stay put.
  7. Gravity is right in each mode — you fall in side-scroll, you don't in top-down.
  8. Dash, double jump and glide all work in side-scroll and do nothing in 3D.

Step 6 is the one that kills hybrid games. Test it deliberately: switch to 2D, run back and forth for ten seconds, switch to 3D, look at where you are. If you've drifted, your reposition point isn't set.


11. Then add

  1. One complete area — a 3D room, a doorway, a 2D section, a doorway back.
  2. Art. Only now. Your Egyptian setting is strong and the 3D sections will carry most of it.
  3. Animation for the 2D body — Guide B §B6, plus Dash, DoubleJump, IsGliding.
  4. The barque as a hub — a 3D space you return to between trials.
  5. Apep as a boss (Guide 7 §9), probably in a 2D section where the camera can frame him.
  6. More areas, each mixing modes differently.

12. Design notes for your game specifically

Prototype first. I've said it three times because it's the whole guide. Everything else here is standard platforming and standard first-person walking. The only genuinely novel thing in your project is whether the switch feels good, and that's answerable in two hours with grey boxes.

The switch should mean something. A perspective change that's purely decorative gets old fast. The interesting version is when the same space reads differently in two views — a gap that looks impassable in 3D turns out to be a simple jump in 2D, or a path hidden behind a pillar in first-person is obvious from above. That's what Fez and Shady Part of Me do, and it's why you listed them.

Fewer, better transitions. Two well-designed switches per area beats ten. Each one costs the player a moment of disorientation, and that budget is finite.

Reposition points are not optional. Every single ModeSwitchTrigger that enters a 2D mode needs one. Make it a habit: place the trigger, place the point, drag it in. Skipping one gives you a bug that appears twenty minutes into playtesting and takes an hour to diagnose.

The 3D sections don't need to be complicated. First-person walking through an Egyptian barque, looking at things, finding a doorway — that's enough. Your budget should go into the 2D sections where the movement abilities live.

Your theme is doing a lot of work. Ra's nightly journey through the underworld is already a sequence of distinct realms, which is a perfect excuse for perspective changes. Lean on that: each mode switch can be a passage into a different part of the night.


13. Common problems

What you see What's wrong
Camera snaps instead of blending No CinemachineBrain on Main Camera, or Default Blend is 0
Nothing happens on switch Controllers not assigned in CameraModeSwitcher
Two controllers fight Both enabled — the switcher should manage this; check Manage Bodies ✓
Player floats in side-scroll Rigidbody2D.simulated off, or Manage Bodies unticked
Player falls in top-down Gravity not zeroed — Manage Bodies ✓ handles it
Player drifts off the 2D plane Reposition Player To not assigned on the trigger
Player phases through the level in 2D Same cause — wrong Z
Can move during the blend Lock Input During Blend unticked
Mouse stays locked in 2D Controller 3D not assigned, so the switcher can't unlock it
Falls through the floor in 3D CharacterController disabled, or the floor has no 3D collider
Falls through the floor in 2D Ground has no 2D collider, or it's on the wrong layer
Dash works in 3D Expected — it does nothing there because PlayerController2D is disabled. If it moves you, check the module isn't reading a stale controller

14. Checklist