FERRETGame engine over Babylon.js
Ferret

@ferret/character

Character movement (capsule, walk, run, jump, steps, slopes), cameras and the player controller.

12 exports · source in packages/character/src

Classes

CameraRig class

class CameraRig

The player's camera: first or third person, switchable at run time. The third-person boom is a spring arm: it is shortened when a wall is in the way, so the camera never clips into the level. Inputs of Babylon's own are removed.

readonly camera: BABYLON.FreeCamera
view: ViewMode
yaw: number
pitch: number
distance: number
currentDistance: numberthe boom length actually used after collision
readonly o: Required<Omit<CameraRigOptions, 'mask'>> & { mask: number }
boom: ExternalBoom | nulla boom fixed on something else than the character (a ride); update uses it in place of the first/third person camera while it is set
constructor(scene: BABYLON.Scene, private physics: PhysicsService, opts: CameraRigOptions = {})
toggleView()
setView(v: ViewMode)
zoom(delta: number)
look(dyaw: number, dpitch: number)
groundForward(out = new BABYLON.Vector3())Forward on the ground plane for the current yaw (what "move forward" means).
groundRight(out = new BABYLON.Vector3())
setBoom(b: ExternalBoom | null)Fix the camera on a boom of its own (or back on the character with null).
blendFromCurrent(duration: number, exp = 2)Start a timed blend from where the camera is now to wherever update puts it (UE: SetViewTargetWithBlend, ease in-out).
get blending()
update(feet: BABYLON.Vector3, dt: number)Place the camera for a rendered frame; feet is the interpolated position of the character.

packages/character/src/camera.ts:45

CharacterMovement class

class CharacterMovement extends Component<CharacterParams>

Capsule character movement against static geometry: walk, run, crouch, jump, step up, slopes, ground snapping, moving platforms. The same component moves the player and NPCs; they differ only in who sets the move input. The entity's node must be a Babylon Mesh (it carries the collision ellipsoid); its origin is at the feet.

p: Required<Omit<CharacterParams, 'groundMask'>> & { groundMask?: string[] }
velocity: Vector3
grounded: boolean
groundNormal: Vector3
groundMesh: BABYLON.AbstractMesh | null
crouching: boolean
running: boolean
submerged: number0..1: the part of the body inside water or mud (capability D); swimming when most of it is and the feet are off the ground
swimming: boolean
yaw: number
flying: booleanflying (UE: MOVE_Flying): no gravity, no ground; the vertical speed follows setVerticalInput times verticalSpeed; the horizontal speed is walk/run speed as on the ground
verticalSpeed: numberm/s at full vertical input in flying mode
prevPosition: Vector3where the body was at the previous fixed step (camera interpolation)
get mesh(): BABYLON.Mesh
get height()
get speed2d()
onAttach()
onDetach()
setMoveInput(dir: BABYLON.Vector3, run = false)Desired movement in world space; its length (0..1) scales the speed. The vertical part is used only while swimming: Unreal swims along the view direction, pitch included.
jump()
setVerticalInput(v: number)Flying mode: -1..1, up positive.
setFlying(on: boolean)Switch flying mode on or off (off: the character falls and lands by the normal rules).
motionState()what an Animator needs to know (see MotionSource in
setCrouch(on: boolean)
shift(d: BABYLON.Vector3): BABYLON.Vector3Move the capsule horizontally by d now, with collisions and step-ups, outside the velocity model (room-scale VR: the player walked in the room). Returns the distance actually moved.
teleport(pos: BABYLON.Vector3)
onFixedUpdate(dt: number)
renderPosition(alpha: number, out = new BABYLON.Vector3())The interpolated position for the render frame (the camera follows this).

packages/character/src/movement.ts:70

PlayerController class

class PlayerController extends Component<PlayerParams>

The player controller: input actions -> movement and camera. First and third person; the third-person body faces where it moves, the first-person body faces where the camera looks.

viewOverride: ViewOverride | nullAnother owner of the view (a VR headset: the head owns the camera). While it is set, the controller does not move or aim the camera rig, look / turn are left to the owner, and "forward" is yaw().
rig: CameraRig
movement: CharacterMovement
onAttach()
get view(): ViewMode
setView(v: ViewMode)
toggleView()
onFixedUpdate(dt: number)
onUpdate(dt: number)
onDetach()

packages/character/src/player.ts:41

Functions

easeInOut function

function easeInOut(a: number, exp = 2): number

UE's FMath::InterpEaseInOut(0, 1, a, exp): slow at both ends.

packages/character/src/camera.ts:6

spawnCharacter function

function spawnCharacter(world: World, name: string, position: BABYLON.Vector3, params: CharacterParams & { layer?: string } = {}): { entity: Entity; movement: CharacterMovement; mesh: BABYLON.Mesh }

A character entity: an invisible Mesh with the collision ellipsoid, a Collider on the Pawn layer and CharacterMovement.

packages/character/src/movement.ts:433

Interfaces

CameraRigOptions interface

interface CameraRigOptions
view?: ViewMode
eyeHeight?: numbermetres above the feet where the eyes are (first person) and the boom pivots (third person)
distance?: numberthird person: distance behind the pivot, and its limits for zoom
minDistance?: number
maxDistance?: number
shoulder?: numberthird person: sideways offset of the pivot (over the shoulder)
pitchMin?: number
pitchMax?: number
probe?: numberthird person: radius kept free between the camera and the walls
mask?: numberlayers the spring arm collides with

packages/character/src/camera.ts:23

CharacterParams interface

interface CharacterParams

Parameters follow UE's Character Movement Component, in metres and seconds.

radius?: number
height?: number
crouchHeight?: number
eyeHeight?: number
walkSpeed?: number
runSpeed?: number
crouchSpeed?: number
jumpVelocity?: numberinitial vertical speed of a jump (UE: JumpZVelocity)
gravity?: number
mass?: numberkg: how much push a character has against water or mud (capability D), with thrust
bodyDensity?: numberkg/m³: below the density of the water it floats, above it sinks (people are about 985)
thrust?: numberm/s²: the push the character can make against drag in a medium (swimming, wading); the speed it reaches there follows from it
swimSpeed?: numberm/s: UE MaxSwimSpeed. Set, a character in a dense medium (swimming) moves at exactly this speed whatever the walk, run or crouch state, as Unreal's swimming mode does; unset, the speed follows from thrust and the drag
buoyancy?: numberUE Buoyancy: 1 = neutral (the weight is carried completely in the medium), below 1 sinks, above 1 rises. Unset: the density ratio medium / bodyDensity decides
outOfWaterZ?: numberUE OutofWaterZ, m/s: the upward speed of the water jump (swimming against a ledge, the input pointing up)
jumpOutOfWaterPitch?: numberUE JumpOutOfWaterPitch, degrees: the water jump needs the swim input to point at least this far above the horizon
maxOutOfWaterStepHeight?: numberUE MaxOutOfWaterStepHeight, m: how far above the body's centre the ledge may be for a water jump
swimAcceleration?: numberm/s²: UE MaxAcceleration while swimming (the push along the 3D swim input)
fluidFriction?: numberUE PhysicsVolume FluidFriction (0.3 by default) of the water; with BrakingDecelerationSwimming 0 a stopped swimmer coasts by it times BrakingFrictionFactor 2
maxWindAccel?: numberm/s²: the most the wind (the flow service) can push the character; 0 turns the wind off for it (a game's cap)
maxStepHeight?: number
walkableAngle?: numbersteepest slope that can be walked, degrees (UE: WalkableFloorAngle)
acceleration?: number
braking?: number
airControl?: numberfraction of the ground acceleration available in the air
snapDistance?: numberhow far below the feet the ground is still "ground" when walking down
groundMask?: string[]layer names the character collides with when probing the ground
faceMovement?: booleanturn the body to face where it moves (third person); first person sets the yaw from the camera
turnRate?: number
flyAcceleration?: numberflying mode: m/s²: how fast the vertical speed follows setVerticalInput

packages/character/src/movement.ts:5

ExternalBoom interface

interface ExternalBoom

A boom on a point of the game's own (a mount's seat): UE's spring arm with camera lag and an absolute rotation.

pivot: () => BABYLON.Vector3where the boom is fixed, world space, metres (read every frame)
arm: numberboom length, metres
socketZ?: numberlift of the camera above the boom's end (UE: SocketOffset.Z), metres
lag?: numbercamera lag speed (UE: CameraLagSpeed); 0 = no lag

packages/character/src/camera.ts:12

PlayerActions interface

interface PlayerActions

The names of the game's actions that the controller reads. Anything left out is simply not used.

move?: string
look?: string
turn?: string
jump?: string
run?: string
crouch?: string
view?: string
zoom?: string

packages/character/src/player.ts:8

PlayerParams interface

interface PlayerParams
actions?: PlayerActions
camera?: CameraRigOptions
turnSpeed?: numberrad/s at full turn
alwaysRun?: booleana console has no run button: run when the stick is fully pushed, or always
bodyInFirstPerson?: booleanfirst person: show the body (arms/legs)
body?: BABYLON.AbstractMesh[]meshes that make up the visible body; hidden in first person unless bodyInFirstPerson

packages/character/src/player.ts:19

ViewOverride interface

interface ViewOverride
yaw(): numberthe yaw "move forward" follows, radians

packages/character/src/player.ts:32

Types

ViewMode type

type ViewMode = 'first' | 'third'

packages/character/src/camera.ts:3