@pixi/3d
    Preparing search index...

    Class FPSCamera

    First-person controller for a View3D's camera

    Drag, or move the mouse under pointer lock, to look around. WASD or the arrow keys walk and strafe, and Space and Shift move along world Y. The move vector takes input from anything else, such as an on-screen joystick.

    A look drag or pointer lock starts from a press on the View, within its hitArea. The controller blocks the browser's context menu over the View so a right-button drag can look around; see preventContextMenu.

    import { FPSCamera } from '@pixi/3d/extras';

    const fpsCamera = new FPSCamera({
    view: view3d,
    position: { x: 0, y: 1.7, z: 5 },
    pointerLock: true,
    moveSpeed: 6,
    });

    fpsCamera.on('lock', () => (hud.hidden = true));
    fpsCamera.on('unlock', () => (hud.hidden = false));

    // On teardown:
    fpsCamera.destroy();

    Hierarchy

    • EventEmitter<{ change: []; lock: []; unlock: [] }>
      • FPSCamera
    Index
    • Starts listening for input on options.view right away

      Parameters

      Returns FPSCamera

    enabled: boolean

    Whether look input and movement apply

    Disabling it doesn't release pointer lock, so a menu that needs the cursor has to exit the lock itself.

    inventory.on('open', () => {
    fpsCamera.enabled = false;
    document.exitPointerLock();
    });
    lookSpeed: number = 0

    Look sensitivity in radians per pixel

    fpsCamera.lookSpeed = 0.002 * settings.mouseSensitivity;
    
    maxPitch: number = 0

    Pitch clamp in radians

    fpsCamera.maxPitch = Math.PI / 3;
    
    move: Vector3 = ...

    Movement input from outside the keyboard, each axis -1 to 1

    x strafes right, y rises along world Y and z walks forward. It adds to the keys on every update, so the camera keeps moving until you set it back to zero.

    app.ticker.add(() => {
    const pad = navigator.getGamepads()[0];

    if (pad) fpsCamera.move.set(pad.axes[0], 0, -pad.axes[1]);
    });
    moveSpeed: number = 0

    Movement speed in world units per second

    Diagonal input isn't normalised, so moving forward and sideways at once is about 1.4 times faster.

    window.addEventListener('keydown', (event) => {
    if (event.code === 'ControlLeft') fpsCamera.moveSpeed = 10;
    });
    window.addEventListener('keyup', (event) => {
    if (event.code === 'ControlLeft') fpsCamera.moveSpeed = 5;
    });
    pointerLock: boolean

    Request pointer lock on the canvas when the View is pressed, so the mouse looks around without a button held

    Only a mouse press requests the lock; touch and pen still look by dragging.

    fpsCamera.pointerLock = settings.captureMouse;
    
    preventContextMenu: boolean

    Whether the browser's context menu is kept from opening over the View, so a right-button drag doesn't open it

    It applies only within the View's hitArea and only while enabled is on. On Windows the menu opens on release, so a right-button drag that ends outside the View still opens it.

    fpsCamera.preventContextMenu = false;
    
    view: View3D

    The View3D this controller listens on and whose camera it drives

    fpsCamera.view.cursor = 'crosshair';
    
    defaultOptions: Partial<Omit<FPSCameraOptions, "view">> = ...

    Defaults for every new FPSCamera; an option passed as undefined keeps its default

    FPSCamera.defaultOptions.pointerLock = true;
    
    • get autoUpdate(): boolean

      Whether update() runs from Ticker.shared every frame

      OrbitCamera#autoUpdate explains why updating from app.ticker keeps movement in step with the render.

      Returns boolean

      fpsCamera.autoUpdate = false;
      app.ticker.add((ticker) => fpsCamera.update(ticker));
    • set autoUpdate(value: boolean): void

      Sets whether update() runs from Ticker.shared

      Parameters

      • value: boolean

        true to update every frame

      Returns void

    • get camera(): Camera3D

      The Camera3D being driven, always view.camera

      Its rotation belongs to the controller, and the next look input overwrites a rotation set on the camera directly. Turn it with yaw and pitch.

      Returns Camera3D

      fpsCamera.on('change', () => {
      if (fpsCamera.camera.position.y < -10) respawn();
      });
    • get keyboard(): boolean

      Whether WASD / arrow keys, Space and Shift are read from window

      Keys are matched by position (KeyboardEvent.code), so the same physical keys work on any keyboard layout.

      Returns boolean

      chatInput.addEventListener('focus', () => (fpsCamera.keyboard = false));
      chatInput.addEventListener('blur', () => (fpsCamera.keyboard = true));
    • set keyboard(value: boolean): void

      Sets whether movement keys are read from window

      Parameters

      • value: boolean

        true to read them

      Returns void

    • get locked(): boolean

      Whether the canvas currently holds pointer lock for this controller

      Returns boolean

      app.ticker.add(() => (clickToPlay.visible = fpsCamera.pointerLock && !fpsCamera.locked));
      
    • get pitch(): number

      Pitch in radians, clamped to ±maxPitch: 0 is level, and positive values look up

      Returns number

      fpsCamera.pitch = 0;
      
    • set pitch(value: number): void

      Sets the pitch and tilts the camera

      Parameters

      • value: number

        Pitch in radians; clamped to ±maxPitch

      Returns void

    • get yaw(): number

      Yaw in radians, around world Y: 0 faces -Z, and positive values turn left

      Returns number

      window.addEventListener('keydown', (event) => {
      if (event.code === 'KeyQ') fpsCamera.yaw += Math.PI / 4;
      });
    • set yaw(value: number): void

      Sets the yaw and turns the camera

      Parameters

      • value: number

        Yaw in radians; unbounded

      Returns void

    • Removes its input listeners and every change, lock and unlock listener, exits pointer lock and stops auto-updating

      The View and its camera are left as they are.

      Returns void

      fpsCamera.destroy();
      const orbit = new OrbitCamera({ view: view3d });
    • Moves the camera by this frame's movement input

      Runs every frame while autoUpdate is on; call it yourself every frame when it's off. Does nothing while enabled is off.

      Walking follows the full view direction, pitch included, so walking forward while looking down descends. Strafing stays level, and Space and Shift move along world Y whatever the pitch.

      Parameters

      • Optionalticker: Ticker

        The ticker driving this update; supplies the frame time. Omitted, one 60 fps frame is assumed.

      Returns boolean

      true when the camera moved

      fpsCamera.autoUpdate = false;
      app.ticker.add((ticker) => {
      if (fpsCamera.update(ticker)) resolveWallCollisions(fpsCamera.camera.position);
      });