API / Input

Input

Read device state and build context-owned actions and axes.

InputSystem is available from game.input. For gameplay bindings, create an action map from that system. The Game loop polls it once per frame before calling update.

Actions and bindings

typescript
import { Game, Key, MouseButton, Vector2D } from '@bornengine/engine';
const game = new Game();
const controls = game.input.createActionMap();
controls.bindAction('fire', [
  { kind: 'key', key: Key.SPACE },
  { kind: 'mouse', button: MouseButton.LEFT },
]);
controls.bindAxis('move', {
  negative: [{ kind: 'key', key: Key.A }],
  positive: [{ kind: 'key', key: Key.D }],
  gamepadAxis: { axis: 0, deadzone: 0.15 },
});
controls.bindAxis('move-y', {
  negative: [{ kind: 'key', key: Key.W }],
  positive: [{ kind: 'key', key: Key.S }],
});

Bindings combine with OR. Invalid names, indices, rectangles, scales, or deadzones return false and leave the previous mapping unchanged.

Snapshots and edges

isDown, wasPressed, wasReleased, and axis reads use the map’s latest snapshot. Game advances each map once per frame before update, so edge values remain stable throughout that callback.

typescript
if (controls.wasPressed('fire')) fireWeapon();
if (controls.isDown('fire')) chargeWeapon();
const horizontal = controls.readAxis('move');

If you drive a custom loop outside Game.run, call game.input.update() once before reading the map. Do not update the same map twice in one frame.

Axes and rebinding

Axes combine digital negative/positive bindings with an optional analog gamepad axis. Values are clamped to [-1, 1], deadzoned, then scaled. readVector2(horizontal, vertical) combines two named axes.

typescript
controls.bindAxis('move-x', {
  negative: [{ kind: 'key', key: Key.LEFT }],
  positive: [{ kind: 'key', key: Key.RIGHT }],
});
controls.bindAction('confirm', { kind: 'key', key: Key.ENTER });
const movement = controls.readVector2('move', 'move-y');
const normalizedMovement = Vector2D.clampMagnitude(movement, 1);

readVector2() returns a Vector2D value, ready for vector math. Use toData() and loadData() to save and restore bindings. loadData() validates the full versioned record before replacing anything, then resets edge state so held inputs do not appear as new presses after rebinding. See Game storage for persistent JSON saves on Web.

Frame loop

Game.run() polls input before update(deltaTime). Prefer that lifecycle so keyboard, mouse, gamepad, touch, and action-map snapshots share a single frame boundary.

Capture the pointer for mouse-look controls and release it when opening menus:

typescript
game.input.setCursorCaptured(true);
game.input.setCursorCaptured(false);

The method returns false if the input system is unavailable and true when the request is accepted.

Device behavior

Use direct methods such as game.input.isKeyDown(key), game.input.getMousePosition(), game.input.getTouchPosition(index), and game.input.isGamepadAvailable(id) for low-level device access. The primary gamepad is selected by the input adapter. Touch regions use the same screen coordinate space as the window; game.input.isTouchActive(index) distinguishes a live touch from an empty slot.