logo

Install with the CLI:

bjs download Score

Score

Per-player point tracking — a shared, renderer-agnostic substrate any game can award points into.

What it does

Score is data-only: it keeps a clamped, deterministic point bucket per player (or any string entity id) and never touches the renderer. The System wires its core to the EventBus — it listens for score.add (direct point awards) and goal.scored (so Goal-mechanic scenes work out of the box), pipes points through the core, and rebroadcasts every change as score.changed. A score.resetRequest clears every bucket and fires a single score.reset. Presentation — scoreboard HUDs, celebration VFX, end-match rankings — lives in sibling systems that subscribe to these events.

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.

Fastest path

bjs download scene Score

Pulls this exact scene into your project and runs it — no copy-paste. Add --all to grab the components and assets it needs too.

Or 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 Score
    bjs download Score

    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
{
  "ScoreState": {
    "components": {
      "Score": {
        "defaultPoints": 100,
        "scores": { "Player": 0 }
      }
    }
  }
}

Props

  • defaultPoints (number, default 1) — points awarded per add when none is passed in the event.
  • minScore (number | null, default null) — lower bound a score can reach; null = no clamp.
  • maxScore (number | null, default null) — upper bound a score can reach; null = no clamp.
  • scores (Record<string, number>, default {}) — seeded starting scores keyed by player/entity id.

Events

  • Emits score.changed (ScoreEvents.CHANGED) on every point change, with { ownerEntity, score, delta, allScores }.
  • Emits score.reset (ScoreEvents.RESET) once when all buckets are cleared, with { allScores }.
  • Listens for score.add (ScoreInputEvents.ADD) — { ownerEntity, points? }.
  • Listens for score.resetRequest (ScoreInputEvents.RESET) — {}.
  • Listens for goal.scored (ScoreInputEvents.GOAL_SCORED) — { ownerEntity?, points? }, routed straight into an add.

Notes

  • Single-scoreboard: the System routes all events into the first entity with a Score instance, so keep one Score entity per scene.
  • delta on score.changed is the points actually applied after clamping, which can differ from the requested amount.
  • serialize() prefers the live instance's current scores over the seed, so a save/load round-trip preserves in-progress gameplay.
  • Tightening minScore / maxScore at runtime re-clamps existing buckets immediately.

More like this

Bumper
Goal
MouseHole
Scoreboard
SoccerDirector
Spinner
TwinStickEnemy
AiPilot
Animation
ArcCamera
Asteroid
Bullet
CameraFollow
CardFan
DirectionalLight
EnemySpawner
EnvironmentTexture
FreighterCar
FreighterChain
FreighterHead
GameConfig
Health
HealthBar
HemisphericLight
Jump
KeyboardInput
KeyboardMover
Lifetime
LineOfSight
MachineGun
Mesh
MeshPrimitive
Missile
MissileLauncher
MissionDirector
MouseInput
Movement
Obstacle
ObstacleField
OilBlob
Parts
Physics
PlayerInput
PlayerWalkAnimator
PokerHUD
PokerTableCards
RespawnTimer
RoundReset
Shadow
ShipLoadout
SkeletonAnimator
SpaceShooterBullet
SpaceShooterHUD
SpaceShooterHealth
SpaceShooterScore
Transform6DOF
WaveDirector
Waypoint
WaypointTrack

Was this page helpful?

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

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search