logo
Unlock

Install with the CLI:

bjs download PinballDirector

PinballDirector

The rules of a game of pinball: three balls, ball save, a bonus that pays when the ball drains, and a jackpot.

What it does

Every pinball machine since the 1930s runs the same loop. You get a set number of balls. The score only goes up. A bonus builds while the ball is alive and pays out, times a multiplier, when it drains. This component is that loop.

It never touches the ball or the table. It listens to what the parts say, and asks other parts to act:

  • A new game clears the score and stands the drop targets up, then asks the Plunger to serve ball 1 (plunger.serve).
  • plunger.launched puts the ball in play, and ball save starts counting down.
  • plunger.drained inside ball save serves the same ball again: BALL SAVED.
  • plunger.drained after ball save pays the bonus and serves the next ball. After the last ball it says GAME OVER and asks the plunger to park the ball (plunger.park).
  • Bumpers, slingshots, spinner turns, lanes and drop targets each add bonusPerSwitch to the bonus.
  • A made ramp adds bonusPerRamp, and every rampsPerMultiplier ramps the multiplier goes up one. So does a finished set of lanes.
  • A finished bank of drop targets lights the jackpot. The saucer (MouseHole) collects it.

Here is one ball with the default rules. Twelve switches and a spinner that turns 5 times make 17 × 10 = 170. Two ramps add 1,000 and make it 2X. A lane set makes it 3X. The ball drains after ball save, and the bonus pays 1,170 × 3 = 3,510.

It says the whole game on pinball.game.changed every time anything moves, so a HUD only draws what it is told. Short news goes out on pinball.game.message: BALL SAVED, BONUS 3X, JACKPOT 25,000, GAME OVER.

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

    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": 0, "scores": { "Player": 0 } }
    }
  },
  "World": {
    "components": {
      "Plunger": {
        "spawnPosition": [7.1, 0.42, 14.1],
        "launchVelocityZ": -30,
        "chargeSeconds": 0.9,
        "autoLaunch": false,
        "returnRadius": 0.7,
        "rod": "Plunger_Rod"
      }
    }
  },
  "Game": {
    "components": {
      "PinballDirector": { "balls": 3, "ballSave": 8, "jackpot": 0 },
      "PinballHUD": { "title": "PINBALL" }
    }
  }
}

Set the Plunger's autoLaunch to false, so it waits for the director to serve each ball. Set jackpot to 0 on a table with no saucer, so the jackpot never lights.

Props

  • balls (number, default 3). Balls per game.
  • ballSave (number, default 8). Seconds after a launch when a drain gives the ball back. 0 is off.
  • ownerEntity (string, default "Player"). The Score bucket it reads and pays into.
  • bonusPerSwitch (number, default 10). Bonus for each switch hit.
  • bonusPerRamp (number, default 500). Bonus for each made ramp.
  • rampsPerMultiplier (number, default 2). Ramps it takes to raise the multiplier by one.
  • maxMultiplier (number, default 5). The highest the multiplier goes.
  • jackpot (number, default 25000). What the saucer pays while the jackpot is lit. 0 is no jackpot.
  • startKey (string, default "Enter"). Key code that starts a game between games.
  • autoStart (boolean, default true). Start the first game without waiting for the key.

Events

Emits:

  • pinball.game.changed. The whole game: phase (attract, ready, playing or over), ball, balls, score, bonus, multiplier, ramps, saveLeft, jackpotLit, best.
  • pinball.game.message, { text, kind }. kind is info, award or warn.
  • plunger.serve and plunger.park. To the plunger.
  • score.add. The bonus and the jackpot.
  • score.resetRequest and dropTarget.resetRequest. At the start of each game.

Listens to:

  • pinball.game.start and keyboard.keydown. Start a game.
  • plunger.launched and plunger.drained.
  • score.changed and score.reset. The score it shows, and the best.
  • bumper.hit, slingshot.kicked, spinner.spun, rollover.changed, dropTarget.down. Bonus.
  • pinballRamp.made and rollover.complete. Multiplier.
  • dropTarget.bankComplete and mouseHole.captured. Jackpot.

Dependencies

None in code. It talks to the other parts only through events, so a table can leave any of them out. It needs a Plunger with autoLaunch off and a Score to be a game.

Notes

  • A lit jackpot does not carry over to the next ball.
  • best is the highest score since the page loaded. It is not saved.

More like this

Was this page helpful?

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

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search