The pack
controls2d
function controls2d(opts: ControlsOptions = {}): Pack<{ controls: ControlsApi }>
The 2D controls pack. Samples every player's intents once per fixed step (controls-2d.intents hook) from
keyboard, gamepad and touch codes, and returns controls. Requires a 2D world, for the pointer's world position.
Functions
resolveBindings
function resolveBindings(opts: ControlsOptions = {}): PlayerBindings[]
The bindings the options describe, one per player. Throws on a malformed set.
Constants
DEFAULT_BINDINGS
const DEFAULT_BINDINGS: PlayerBindings
The defaults, for one player: WASD and the arrows move; Space or J fire, E or K action, Escape pause; pad A, B and Start; the first connected pad, its left stick moving and its right stick aiming.
Types
AimOrigin
interface AimOrigin
A point the aim axis is measured from: the player, usually. Anything with a live x and y will do.
readonly x: number— World x.readonly y: number— World y.
Axis
type Axis = 'move' | 'aim'
The two axes: move from keys or a stick, aim from the pointer or the right stick, measured from the aim origin.
ControlsApi
interface ControlsApi extends PlayerControls
game.controls: player 0's controls, every player's, and the pointer.
player(n: number): PlayerControls— Playern's controls. Throws for a player the options did not configure.readonly players: number— How many players are configured.readonly pointer: { x: number; y: number; down: boolean; pressed: boolean; released: boolean } | null— The pointer in WORLD units, or null.pressed/releasedwent down / up since the last step, latched by the kernel: read them for a tap, notdownfrom step to step, which misses a click shorter than a frame.
ControlsOptions
interface ControlsOptions
Manifest options.
bindings?: { move?: Partial<MoveKeys>; intents?: Record<string, IntentBinding | null>; pad?: number | 'any' | 'none'; stick?: 'left' | 'right' }— Overrides for the single player, merged overDEFAULT_BINDINGS:movereplaces the directions it names,intentsreplaces the intents it names (null removes one),padandstickreplace. Ignored whenplayersis given.players?: PlayerBindings[]— Two or more players, each bound in full (nothing is merged, so two players never share the defaults). A player withoutpadgets the pad in its own slot. At most 4.aimDeadzone?: number— A pointer closer than this, world units, to the aim origin gives aim{0, 0}. Default 12.
IntentBinding
interface IntentBinding
What drives one intent: any key in keys or any pad button in pad.
keys?: string[]— Key codes (KeyboardEvent.code, or a code a touch control presses, such as'Touch:fire').pad?: string[]— Gamepad button names:a b x y lb rb lt rt back start ls rs up down left right.
MoveKeys
interface MoveKeys
Key codes (KeyboardEvent.code) per direction; any held key counts.
up: string[]— Keys that push up (negative y).down: string[]— Keys that push down (positive y).left: string[]— Keys that push left (negative x).right: string[]— Keys that push right (positive x).
PlayerBindings
interface PlayerBindings
One player's bindings.
move?: MoveKeys— Keys per direction for the move axis. Omit for a pad-only player.intents: Record<string, IntentBinding>— The intents, by any name the game chooses (fire,jump,dash…).pad?: number | 'any' | 'none'— Which gamepad drives this player: a slot index,'any'for the first connected pad, or'none'.stick?: 'left' | 'right'— The pad's stick for the move axis; the other stick aims. Default'left'.
PlayerControls
interface PlayerControls
One player's controls: intents and axes, never keys.
readonly index: number— This player's index, from 0.axis(name: Axis): { x: number; y: number }— A direction of length ≤ 1.move: the keys (digital) or else the move stick (analogue); the game cannot tell.aim: the aim stick when it is pushed, else a unit vector from the aim origin to the pointer;{0, 0}with neither, or with the pointer withinaimDeadzoneof the origin.pressed(intent: string): boolean— Held this fixed step. An intent this player has no binding for throws, naming the bound ones.justPressed(intent: string): boolean— True for exactly one fixed step, even for a key tapped down and up between two steps.justReleased(intent: string): boolean— True for the one fixed step after the intent was let go.aimFrom(origin: AimOrigin | null): void— Measureaimfrom this point (the player); null measures from the camera's centre. Scene-scoped.bind(intent: string, binding: IntentBinding | null): void— Rebind an intent, or add a new one; null removes it. Lasts until rebound: a settings screen calls it.bindMove(keys: MoveKeys | null): void— Rebind the move keys; null leaves the move axis to the pad.usePad(pad: number | 'any' | 'none'): void— Change which pad drives this player.bindings(): PlayerBindings— A copy of the current bindings, for a settings screen or a save.


