logo

Babylon.js Market

FlightIntent

input · space-combat-sim

FlightIntent

1
Unlock

Install with the CLI:

bjs download FlightIntent

FlightIntent

The normalised "stick and throttle" a player or AI pilot fills each frame to fly a 6-DOF ship.

What it does

FlightIntentComponent is pure data — five numbers that say what the pilot wants this frame, nothing about how the ship answers. Three axes hold pitch, yaw, and roll in [-1, 1], throttle sits in [0, 1], and boost is a flag. It owns no System of its own; the tier file just re-exports the core so the registry can resolve the name. A producer writes it — PlayerFlightInput maps the keyboard onto it (arrows pitch/yaw, A/Q · D/E roll, W/S throttle, Shift boost), or an AI pilot fills the same fields from a steering brain — and a consumer, the FlightControlSystem that ships with ShipFlight, reads it plus the ship's tuning and turns throttle · maxThrust · (boost ? boostMultiplier : 1) into forward thrust and the axes into body-frame angular acceleration, written out to Velocity6DOF. Keeping intent separate from tuning is the whole point: one set of controls can fly a twitchy fighter or a sluggish freighter just by swapping the ShipFlight knobs next door.

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 FlightIntent
    bjs download FlightIntent

    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": {
      "Transform6DOF": { "x": 0, "y": 0, "z": 0 },
      "Velocity6DOF": {},
      "FlightIntent": {},
      "ShipFlight": { "maxThrust": 80, "turnRate": 5.0, "rollRate": 8.0 },
      "PlayerFlightInput": { "throttleRate": 1.4 },
      "Renderable": { "shape": "spaceplane", "glbSrc": "/wingman/falconship.glb" }
    }
  }
}

Props

  • pitch (number, default 0) — nose up/down, clamped [-1, 1]; a producer sets it, FlightControlSystem scales it by turnRate.
  • yaw (number, default 0) — nose left/right, clamped [-1, 1]; scaled by turnRate.
  • roll (number, default 0) — bank around the nose, clamped [-1, 1]; scaled by rollRate (the flight law applies the sign flip, so producers leave it un-flipped).
  • throttle (number, default 0) — forward drive, [0, 1]; multiplied by maxThrust. PlayerFlightInput ramps this over time rather than snapping.
  • boost (boolean, default false) — when set, thrust is multiplied by the ship's boostMultiplier.

Events

None. FlightIntent emits nothing and listens for nothing — it's a plain data channel between two systems. Producers write its fields directly; FlightControlSystem reads them directly. There is no bus hop, so nothing to subscribe to.

Dependencies

FlightIntent has no hard dependency of its own, but it's inert without a producer and a consumer on the same entity. Pair it with ShipFlight (its FlightControlSystem is the reader that turns intent into motion) and a writer — PlayerFlightInput for a human-flown ship (which also needs a KeyboardInput singleton in the scene to emit keyboard.keydown / keyboard.keyup), or an AI pilot for a computer-flown one. The motion those systems produce flows through Velocity6DOF (integrated by Movement6DOFSystem) onto Transform6DOF.

Notes

  • Set it, don't accumulate it. pitch/yaw/roll are meant to be recomputed fresh each frame — a released key should zero its axis. throttle is the exception: producers accumulate it toward a target so it ramps smoothly. boost is momentary.
  • Signs are load-bearing. The four axes' signs (and the downstream wz += -roll flip in the flight law) are ported verbatim from the Wingman input path. If the stick feels inverted, the fix is in the producer or in ShipFlight's law — not here.
  • One component, two pilots. Because it's just data, the exact same FlightIntent block flies the player ship (filled by PlayerFlightInput) and every enemy (filled by an AI pilot). Nothing about the component changes between them; only the writer does.
  • Values outside range aren't clamped by the component itself — that's the producer's job. Hand-authoring { "throttle": 0.5 } in the scene just seeds a starting throttle before the first producer write.

More like this

Asteroid
CameraState6DOF
ChaseCamera6DOF
ChaseCameraTarget
Flipper
FreighterCar
FreighterChain
FreighterHead
GameConfig
Jump
KeyboardInput
KeyboardMover
OilBlob
PinballBuilderInput
PlayerFlightInput
PlayerInput
PlayerInputBridge
Plunger
PokerInput
Renderable
ShipFlight
SpaceDust
SpaceShooterBullet
SpaceShooterHealth
SpaceShooterScore
Transform6DOF
Velocity6DOF
WaveDirector
Waypoint
WaypointTrack
WorldOriginAnchor

Was this page helpful?

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

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search