Skip to content

First-Person Controller

Write a first-person character controller - WASD movement, mouse-look, and jump, with real capsule collision against the level - as an ordinary script you attach to a player object.

Awaken does not bake a controller into the engine. Instead the engine exposes two generic primitives every game needs - mouse-look input (pointer lock + per-frame mouse deltas) and a capsule move-and-slide helper - and you write the controller logic on top of them as a normal script. This tutorial builds the standard rig on those primitives - a capsule player, a camera the script drives, and a per-frame update that looks, moves, and collides - all using the ScriptApi surface (api.moveAndSlide, api.input) the engine provides for it.

Coming soon

This tutorial is being written. The step outline below is final and the two engine primitives it relies on - api.moveAndSlide and api.input.mouseDX/mouseDY - are already implemented, so you can follow the shape today. Finished prose, a tuned sample script, and screenshots are on the way. A ready-made player prefab shipped as starter content is planned but not yet bundled - for now you assemble the rig yourself, which this tutorial teaches.

What you will build

A player you can walk around a level in first person. The capsule collides with walls and floors (slopes and small steps are handled by the character controller), the mouse looks around after you click to lock the pointer, Space jumps, and the camera follows at eye height. The controller is a single script asset with tunable Inspector params, so you can reuse it in any project.

The rig

  • Player - a GameObject with a capsule Collider at human size (radius ≈ 0.35 m, height ≈ 1.8 m) and the controller Script attached. The capsule is what collides; there is no RigidBody - the character controller is kinematic, so you move it and physics resolves the slide.
  • Camera - an ordinary Camera object that the script keeps at the player's eye height and pitches up/down. You hand it to the script as a camera reference param, so the controller stays generic.

Before you start

Steps

  1. Build the player. Create → Capsule, rename it Player, and add a Collider (kind: capsule, radius 0.35, height 1.8) in the Inspector. See Colliders.

  2. Add a camera. Create → Camera. You will reference it from the script rather than parenting it, so the script can control its exact pose each frame.

  3. Declare the controller's params. In the Code panel, start a ScriptBehavior whose public fields become Inspector controls (see Inspector Parameters):

    ts
    export default class implements ScriptBehavior {
      camera: Entity;               // object picker - assign your Camera
      moveSpeed = 5;                // m/s
      mouseSensitivity = 0.0025;
      jumpHeight = 1.2;             // m
      eyeHeight = 1.6;              // m above the player origin
      gravity = 20;                 // m/s²
    
      private yaw = 0; private pitch = 0; private vy = 0;
      // onUpdate below…
    }
  4. Look. In onUpdate, accumulate yaw -= api.input.mouseDX * this.mouseSensitivity and pitch -= api.input.mouseDY * this.mouseSensitivity (clamp pitch to ≈ ±1.55 rad). Rotate the player body by yaw about world-Y; apply pitch to the camera. Mouse deltas are only non-zero while the pointer is locked - clicking the Game view locks it (api.input.pointerLocked). See Input.

  5. Move. Build a horizontal input vector from WASD in the player's yaw frame and scale by moveSpeed.

  6. Gravity & jump. Integrate this.vy -= this.gravity * dt; if grounded and Space is down, set this.vy = Math.sqrt(2 * this.gravity * this.jumpHeight); zero vy when grounded and falling.

  7. Collide. Move the capsule with the engine primitive and read back whether you landed:

    ts
    const { grounded } = api.moveAndSlide(move.x * dt, this.vy * dt, move.z * dt);

    The capsule is promoted to a kinematic character body on the first call; walls block, slopes and small steps are handled. See Character Controller.

  8. Follow with the camera. Place the camera at playerPos + (0, eyeHeight, 0) with the composed yaw·pitch rotation (reach it via the camera ref).

  9. Attach and assign. Add the Script component to Player, then set the camera param to your Camera object in the Inspector.

  10. Play. Press ▶ Play, click the Game view to lock the pointer, and walk the level. Esc releases the pointer. Press ■ Stop to restore the scene.

📸 Screenshot - save as img/tutorials-fps-controller-params.png

The controller Script component in the Inspector: the camera object-picker (assigned to the scene Camera) above the moveSpeed, mouseSensitivity, jumpHeight, eyeHeight, and gravity fields.

Where to go next

See also

Awaken — browser-native WebGPU game engine.