Third-Person Character Controller
Put an animated character on the screen and drive it - camera-relative WASD, Shift to run, Space to jump - with the animation itself moving the feet (root motion, no foot-slide) and a state graph picking the clip. You assemble it from starter content: a ready-made controller script, a locomotion animation graph, and a player prefab that wires them together. All you supply is a rigged character and its clips.
Like the First-Person Controller, the engine bakes no controller in. It exposes the primitives - a capsule move-and-slide, an animation state graph, per-frame root motion, mouse-look, ragdoll and bone attachment - and the controller is an ordinary script built on top. The difference here is that the character's animation is a first-class input to movement, not a cosmetic layer on top of it.
What you will build
A third-person avatar you can run around a level. WASD moves relative to the camera and the body turns to face the way it moves; the camera orbits behind on a spring arm that pulls in around walls (and fades the character when it tucks in close). On the ground the character moves at the animation's authored speed - the walk and run clips drive the ground movement, so the feet plant instead of sliding. Shift runs, Space jumps, and an AnimStateMachine crossfades idle → walk → run and plays the jump / fall / land clips as the controller reports its state. A long enough fall ragdolls the character, which then gets back up.
The rig
- Third Person Player - a GameObject with a capsule Collider (radius ≈ 0.35 m, height ≈ 1.8 m), the Third Person Controller script, and an AnimStateMachine set to the
tps-locomotiongraph. As with the FPS rig the capsule is kinematic - the controller moves it and move-and-slide resolves the collision. This is exactly what the starter Third Person Player prefab gives you. - Character - your imported rigged mesh (a skinned MeshRenderer + an Animator bound to its skeleton), parented under the player capsule. The controller and the state machine find the character's Animator among their descendants, so the animation state graph on the capsule drives the mesh below it.
- Camera - an ordinary root Camera you hand to the script as its
cameraparam. It must not be parented under the character - the script places the camera itself each frame on a spring arm, so parenting it under the body (which turns) would fight that.
Before you start
- Complete Make Your First Game - the create / script / Play loop.
- Skim the First-Person Controller - the camera-relative WASD and
moveAndSlideideas carry straight over. - Read Animation (skeletons, clips, the Animator, and the AnimStateMachine graph) and Import: Colliders & Skeletons (how rigged characters and clips arrive).
- Have a rigged character and some locomotion clips ready to import. Awaken retargets a clip from one humanoid rig onto another, so a character and an animation pack from different sources still work together.
Steps
1. Import a rigged character and an animation pack
Import your character (a skinned mesh + skeleton) through the import pipeline - its skeleton, skin binding, and Animator are registered for you (see Colliders & Skeletons). Then import your animation pack: a whole pack of clips imports to rig-space clips up front, independent of any one character, and you bind the ones you need per character in a later step. You need at least an idle, a walk, and a run; jump, fall, land, and get-up clips add the rest of the polish.
📸 Screenshot - save as img/tutorials-tps-import.png
The Asset Browser after import: the rigged character with its skeleton, plus a folder of clips from the animation pack.
2. Bring in the player
You have two equivalent routes:
A - Instance the starter prefab (recommended). Import Third Person Player from the starter content and instance it into the scene. It is a capsule already carrying the Third Person Controller script and an AnimStateMachine set to tps-locomotion. If the controller script or the graph is not imported yet, the editor prompts you to locate them - point it at Third Person Controller.awakenscript and Third Person Locomotion.awakenanimgraph from the starter content. See Prefabs.
B - Build it yourself. Add a capsule with a capsule Collider, attach the Third Person Controller script, add an AnimStateMachine component, and pick the tps-locomotion graph on it. (Same components, assembled by hand.)
TIP
The starter files are not part of the engine - a fresh project starts empty. Bring them in via Assets → Import (or drag-drop). The Third Person Controller drives the state machine via params; it does not set clips itself, which is why the graph and its per-character clip bindings are separate pieces.
3. Parent the character and bind its clips
Drag your imported character under the Third Person Player in the Hierarchy so it is a child of the capsule. Position it so its feet sit at the capsule's base.
Now teach the graph which of this character's clips to play. Select the object carrying the AnimStateMachine and, in its clip bindings, map each logical state name to one of your baked clips:
| Logical name | Bind to | Needed for |
|---|---|---|
idle | idle clip | required |
walk | walking clip | required |
run | running clip | required |
jumpStand / jumpWalk / jumpRun | jump-from-stand / -walk / -run | jumping |
shortFall / longFall | falling loops | falling off ledges |
landSoft / landHard | landing clips | landing |
getUp | get-up-from-prone clip | ragdoll recovery |
The bindings live per character on the AnimStateMachine, so the same tps-locomotion graph is reused across the hero and every NPC - each with its own clips. A logical name you leave unbound simply won't play; idle / walk / run is the minimum for a working controller.
📸 Screenshot - save as img/tutorials-tps-clip-bindings.png
The AnimStateMachine in the Inspector: the tps-locomotion graph selected, with the logical clip slots (idle, walk, run, jumpStand…) each bound to one of the character's imported clips.
You can open the graph itself in the editor's Anim Graph tab to see the states and the speed / grounded / fall / land transitions that drive them:
4. Assign a root camera
On the Third Person Controller script, set the camera param to a root Camera in your scene (the object picker filters to cameras). It must not be parented under the character - the script owns the camera's pose, orbiting it behind the character on a spring arm that shortens around walls, and clamping its near-clip so it renders cleanly up close. The script guards against a camera that is the controller's own entity, so keep them separate objects.
📸 Screenshot - save as img/tutorials-tps-params.png
The Third Person Controller in the Inspector: the camera picker assigned to the scene camera, above walkSpeed, runSpeed, turnRate, jumpHeight, the spring-arm distance/height fields, and the fall / ragdoll tuning.
5. Play
Press ▶ Play and click the Game view to lock the pointer. You should see:
- WASD moves the character relative to the camera and the body turns to face its direction of travel.
- On the ground it moves at the animation's speed -
api.rootMotion()feeds the walk/run clip's per-frame horizontal delta intomoveAndSlide, so the feet plant instead of sliding. - Shift runs; the graph crossfades idle → walk → run at its speed thresholds.
- Space jumps. While airborne the script hands vertical control to physics with
setRootMotionVertical(false)(so the clip's own pelvis rise doesn't stack on the physics jump), moves horizontally from input, and the graph plays the jump / fall / land clips as it reportsfallandland. - The camera trails on its spring arm, pulling in and fading the character when it tucks against a wall.
Esc releases the pointer; ■ Stop restores the scene (playback time resets).
📸 Screenshot - save as img/tutorials-tps-play.png
Play mode: the character mid-run through the level, the spring-arm camera trailing behind at chest height.
6. Ship it
Nothing about the animated controller is editor-only. Skeletons, baked clips, skins, the state graph, and its bindings all ride the scene into the container, and the animation system, foot IK, root motion, and ragdoll run in the shipped player - your character animates in the export exactly as it does in Play. Export a single self-contained file with Export game.html and share the link.
Going further
Once the basic controller runs, three engine features extend it - all still working identically in the export:
- Attach gear to a bone. Add a BoneAnchor to an entity and it mirrors a named bone, so a sword under a hand bone (or a hat, a cape) rides the animation. Attach it by parenting the object under the bone in the Hierarchy. See ScriptApi Reference.
- Ragdoll on fatal falls. The controller already calls
api.ragdoll(...)when a fall exceeds itsdeathFallDistance, handing the skinned character to physics as joint-linked bodies that crumple, carrying the impact velocity - then, after it settles, standing it back up with thegetUpclip. You can trigger a ragdoll from your own scripts the same way. (Ragdoll is experimental.) - Grounded feet. Two-bone leg IK plus a pelvis adjust plant the feet on uneven ground while the character is grounded (it's skipped while airborne). It's on by default; nothing to wire.
Limitations (be honest)
- CPU skinning only. There is no GPU skinning path yet - each animated character's deformed mesh is re-uploaded every frame, so this is for a modest number of hero/character objects, not thousands. See Animation.
- No blend spaces / speed-matched locomotion yet. Idle → walk → run is a crossfade at speed thresholds, not a continuously blended, speed-matched locomotion space. It's on the roadmap.
- Up to four bone influences per vertex (the glTF default), and glTF
cubicsplineclips are sampled as linear. - Ragdoll is experimental. A fatal fall crumples the character; if you want it to kick up dust, author a particle effect and fire it from the landing branch with
api.burst("dust", { position: api.getPosition() }).
Where to go next
- Give the character gear and a level with Author a Custom Material.
- Publish your playable build with Ship to a URL or Export game.html.
See also
- Animation - the Animator, the AnimStateMachine graph, and CPU skinning
- Import: Colliders & Skeletons - where rigged characters and clips come from
- Physics: Character Controller - how
moveAndSlideresolves the capsule - ScriptApi Reference -
rootMotion,setAnimParam,setRootMotionVertical,ragdoll, and the full surface - First-Person Controller - the simpler, non-animated sibling
- Prefabs - instancing the Third Person Player starter prefab