Input · class
ActionMap
Explained in Moving things.
class ActionMapimport { ActionMap } from '@driftengine/core';Constructor
new
constructor(input: InputSource, definitions: Readonly<Record<string, ActionDefinition>>)| Parameter | Type | Description |
|---|---|---|
input | InputSource | |
definitions | Readonly<Record<string, ActionDefinition>> |
Accessors
| Name | Type | Description |
|---|---|---|
canRumbleget | boolean | Whether the pad these actions read has motors this browser can drive.MorePad 0, which is the pad every other member of this class already reads. An action map is
one player's controls, so "the pad the actions come from" is the device a rumble belongs on;
a consumer running local multiplayer reaches Grey the control out when this is false. It is re-read rather than cached, because a pad unplugged and plugged back in is a different device behind the same slot. |
Methods
down
down(action: string): booleanWhether anything bound to this action is held.
| Parameter | Type | Description |
|---|---|---|
action | string |
pressed
pressed(action: string): booleanWhether anything bound to it went down since the last poll. Readable by anything.
| Parameter | Type | Description |
|---|---|---|
action | string |
consumePress
consumePress(action: string): booleanThe same edge, claimed: true for exactly one caller.
| Parameter | Type | Description |
|---|---|---|
action | string |
More
Claims through the device rather than keeping its own set, so a claim made here is also
gone from input.keyPressed and from the pad's own pressed. Two claim registers over one
physical press is how a press gets acted on twice.
vector
vector(action: string, out: { x: number; y: number; }): voidFill out with an analog action's direction.
| Parameter | Type | Description |
|---|---|---|
action | string | |
out | { x: number; y: number; } |
More
The larger of stick and keys, never the sum. A player holding a key while pushing the stick the same way is asking to go that way, once; adding the contributions would send them at twice the speed, which is the bug a naive merge ships with. What it costs: the two cannot be combined to exceed the rim, which is the intent. What would make it wrong: an action where two devices genuinely should add, and nothing has asked for one.
This is the reader for a direction. If the two axes are two separate controls — throttle
and steering, pitch and roll — read them one at a time with axis, which does not normalise
them against each other. See its note for what the joint normalisation cost one consumer.
axis
axis(action: string, axis: 'x' | 'y'): numberOne axis of an analog action, on its own, not normalised against the other.
| Parameter | Type | Description |
|---|---|---|
action | string | |
axis | 'x' | 'y' |
More
vector is right for a direction and wrong for two controls, and the difference is not
cosmetic. On foot the two axes are one direction, so a keyboard diagonal must be shortened to
the rim or the player walks faster askew than straight ahead — that is what vector is for and
it should stay the default. At a wheel the same two axes are throttle and steering, which are
two separate controls that happen to share an action: normalising them together means a driver
holding forward and left gets 0.707 of each and can never reach full lock while accelerating.
A consumer lost two weeks to this. The report was "the car does not turn and it is slow", the
whole vehicle model was rewritten looking for it, and it was not in the vehicle model — it was
Math.hypot three call frames away, doing exactly what it was written to do. They shipped four
duplicate digital actions bound to the same keys to get around it.
The pad is unchanged either way: a stick already gives its two axes independently, so a caller driving with one reads the same numbers from both methods. The keyboard is where they part.
rumble
rumble(durationMs: number, strong: number, weak: number): booleanRumble that pad for durationMs, at two magnitudes in [0, 1]. Answers whether it was taken.
| Parameter | Type | Description |
|---|---|---|
durationMs | number | |
strong | number | |
weak | number |
More
false where there is no pad, no actuator, or nothing to play. Never throws.
stopRumble
stopRumble(): booleanStop whatever that pad is playing. Answers whether the platform took it.
bindingsFor
bindingsFor(action: string): readonly Binding[]What currently satisfies an action.
| Parameter | Type | Description |
|---|---|---|
action | string |
rebind
rebind(action: string, binding: Binding): readonly string[]Give an action a binding, and say which actions lost it.
| Parameter | Type | Description |
|---|---|---|
action | string | |
binding | Binding |
More
Reports rather than decides. A binding already serving another action is the interesting case in every rebinding screen there has ever been, and what to do about it is a product decision: steal it silently, warn, or refuse. A consumer that wants uniqueness enforced reads the return and rebinds back.
resetToDefaults
resetToDefaults(action?: string): voidPut one action, or every action, back to what the game shipped with.
| Parameter | Type | Description |
|---|---|---|
action? | string |
save
save(store: KeyValueStore, key: string): voidWrite the bindings a player has actually changed, and nothing else.
| Parameter | Type | Description |
|---|---|---|
store | KeyValueStore | |
key | string |
More
A diff rather than a snapshot, and this is the load-bearing decision. A snapshot freezes the map at the version that saved it: a game that later adds an action, or changes a default nobody had rebound, finds every returning player still on the old set with no way to tell a deliberate choice from a stale record. A diff means an untouched action always follows the current default and only real choices survive an update.
Through KeyValueStore because the engine calls no platform API a consumer might want to
supply differently — the rule that put saves behind this seam.
load
load(store: KeyValueStore, key: string): voidApply a stored record over the defaults.
| Parameter | Type | Description |
|---|---|---|
store | KeyValueStore | |
key | string |
More
An unreadable record is the defaults, reported once. A player whose stored bindings cannot be parsed should get a working game rather than a broken one, and should not have that decided silently — the same shape as every other refusal in this engine.