logo

Babylon.js Market

PlayerInputBridge

input

PlayerInputBridge

Listens toPlayerInput
Talks toMovement
1
Unlock

Install with the CLI:

bjs download PlayerInputBridge

PlayerInputBridge

The missing wire between PlayerInput and Movement — the human equivalent of AIInput.

What it does

PlayerInput publishes input in its own dialect (playerInput.moveChanged, playerInput.actionPressed), but Movement listens for a different one (input.movement.vector, input.jump.requested). Out of the box, a keyboard can't drive the mover — the two components never connect. AIInput already speaks Movement's dialect, which is why an AI entity moves; PlayerInputBridge does the same job for a human.

Drop a PlayerInputBridgeComponent on the same entity that carries PlayerInput and Movement. The PlayerInputBridgeSystem listens for that entity's move-changed events and forwards them verbatim — the XZ payloads are already identical — as input.movement.vector, and translates any configured jump action into input.jump.requested. It only translates input for entities it actually governs (scoped by entityId), so two local players can each carry their own bridge with their own jump map. A pure core (isJumpAction) holds the one decision the bridge makes; both event names are imported as constants, so a rename on either side can't silently desync the bus.

Use it in a scene

A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.

Build it from scratch with the bjs CLI:

  1. 1Scaffold a project
    npm create @babylonjsmarket/arcade@latest my-game

    World, renderer, and dev server — ready to run.

  2. 2Install dependencies
    cd my-game && npm install
  3. 3Add PlayerInputBridge
    bjs download PlayerInputBridge

    Copies its source into src/ so the scene resolves.

    First time? Run bjs login once.

  4. 4Paste the scene into src/scenes/arcade-room.ts and run
    npm run dev

    SceneLoader builds the world from the JSON; reload to rebuild.

JSON
{
  "Player": {
    "tags": ["player"],
    "components": {
      "PlayerInput": {},
      "Movement": { "speed": 6, "groundY": 0 },
      "PlayerInputBridge": { "jumpActions": ["jump"] }
    }
  }
}

Props

  • jumpActions (string[], default ["jump"]) — the PlayerInput action names that fire a Movement jump. Add "attack" to make the primary action double as a jump.

Events

  • Listens for playerInput.moveChanged (PlayerInputEvents.MOVE_CHANGED) — { entityId, x, z }.
  • Listens for playerInput.actionPressed (PlayerInputEvents.ACTION_PRESSED) — { entityId, action, source }.
  • Emits input.movement.vector (MovementInputEvents.SET_MOVEMENT_VECTOR) — { entityId, x, z } — forwarded verbatim.
  • Emits input.jump.requested (MovementInputEvents.JUMP_REQUESTED) — { entityId } — when a pressed action is in jumpActions.

Dependencies

PlayerInput (the emitter it translates) and Movement (the consumer it feeds). Put all three on the same entity.

Notes

  • Pure EventBus relay — no per-frame work, no renderer access.
  • It forwards only for entities that carry the bridge, so an AI entity emitting input.movement.vector directly (via AIInput) and a human routed through the bridge never collide.
  • The move payload is forwarded unchanged because PlayerInput's { entityId, x, z } already matches what Movement expects — the bridge exists for the name mismatch, not a shape mismatch.

More like this

Movement
PlayerInput
AIGoalSeek
AIKick
AIZone
BallPossession
BallPursuit
BallReset
FlightIntent
Flipper
Goal
Jump
KeyboardInput
KeyboardMover
PinballBuilderInput
PlayerFlightInput
Plunger
PokerInput
Scoreboard
SoccerDirector

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search