logo

Babylon.js Market

SpaceShooterHUD

ui · space-combat-sim

SpaceShooterHUD

Listens toRoundReset
2
Unlock

Install with the CLI:

bjs download SpaceShooterHUD

SpaceShooterHUD

The pilot's instruments — reticle, lead diamond, target brackets, lock, hull — drawn over the canvas.

What it does

SpaceShooterHUD reads the world each frame, projects it to screen pixels, and writes positioned DOM over the canvas. It owns no game state: the lock it draws was decided by TargetingSystem (which lives in MissileLauncher), the hull it reads belongs to SpaceShooterHealth, the countdown it shows came from RoundReset.

Colour answers "can I shoot yet" before any number does — cyan tracking, amber locked, green when the crosshair sits on the lead point.

The crosshair is projected at the locked target's distance, not at a fixed range. With a chase camera sitting behind the ship, a point on the nose ray lands on a different pixel depending how far along you sample it — there is no single "forward" pixel. Sample at the target and crosshair-on-target means bullets hit; sample anywhere else and it only means roughly aligned. With no lock it falls back to crosshairFallbackRange.

The lead diamond solves where to aim so bullet and target arrive together. The honest solve is a quadratic; two fixed-point iterations on flight time converge close enough for a dogfight. Effective bullet speed includes the shooter's own velocity along the nose, because bullets inherit ship motion — a ship burning forward genuinely throws them faster.

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

    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
{
  "World": {
    "tags": ["world"],
    "components": {
      "SpaceShooterHUD": { "onTargetPx": 36, "sunMarker": true }
    }
  }
}

Props

  • crosshairFallbackRange (number, default 600) — distance to sample the nose ray when nothing is locked.
  • onTargetPx (number, default 36) — crosshair-to-lead pixel gap that counts as "guns on" and turns both green.
  • playerOcclusionRadius (number, default 65) — screen radius around your own ship where an enemy bracket is suppressed, so a marker never floats on your own hull.
  • shipVisualSize (number, default 5.5) — rough ship envelope in world units, used to size brackets.
  • bracketMinPx / bracketMaxPx (number, defaults 14 / 140) — bracket half-width clamp. Below the floor a distant fighter's bracket collapses to an invisible dot; above the ceiling a close pass fills the screen.
  • fov (number, default 1.05) — fallback vertical FOV for the apparent-size maths. The scene camera's CameraState6DOF.fov wins when there is one.
  • sunMarker (boolean, default true) — mark the sun's projected position.

Events

  • listens for round.reset.pending to show the death overlay and count the restart down, and round.reset.request to clear it.
  • emits nothing. A HUD is a pure consumer.

Dependencies

Transform6DOF, Velocity6DOF, MachineGun, MissileLauncher, SpaceShooterHealth on the player; RoundReset for the death countdown.

Notes

  • Enemy brackets filter on .active. Enemies are pooled and a parked slot keeps its tags, so without the filter the HUD brackets every dead ship sitting in the pool at the origin.
  • A bracket is suppressed only when it overlaps your ship AND has clear line of sight. The second half matters: something tracked behind an asteroid must still draw (dashed, since you can't lock through rock), which is why the lock is line-of-sight-gated separately.
  • FOV is read from the scene camera rather than duplicated. The apparent-size maths is only right if it matches what's actually rendering, and a hardcoded copy with a "must match" comment is the kind of pairing that drifts.
  • Unpauseable, so the death countdown keeps running if the host pauses the world on death.
  • The sun marker dims rather than disappears behind a rock — the sun is the only fixed landmark in an empty sky, so it must not vanish exactly when you want to find it. It's drawn as a starburst because every star in the backdrop is a plain dot; a cross means one thing.
  • The overlay is torn out of the document on shutdown, and guarded by a document check so the System is safe headlessly.

More like this

MachineGun
MissileLauncher
RoundReset
SpaceShooterHealth
Transform6DOF
Velocity6DOF
Asteroid
AsteroidField
CameraState6DOF
CardFan
ChaseCamera6DOF
ChaseCameraTarget
FlightIntent
FreighterCar
FreighterChain
FreighterHead
GameConfig
HealthBar
LensFlare
NebulaSky
OilBlob
PlayerFlightInput
PokerHUD
PokerTableCards
Renderable
Score
Scoreboard
ShipDamageFX
ShipFlight
SpaceDust
SpaceShooterBullet
SpaceShooterFX
SpaceShooterScore
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