logo
Unlock

pinball · pinball

BallSearch

1
Listens toKeyboardInput

Install with the CLI:

bjs download BallSearch

BallSearch

Shakes loose a ball that has stopped where no ball should.

What it does

Pinball machines have done this since the 1980s. If nothing has been hit for a while, the game fires its kickers one at a time to free a ball wedged somewhere the designer did not foresee. Players call it a "ball search."

This watches every ball tagged ball. A ball is stuck when all of these are true for stillSeconds:

  • it stays within stillRadius of one spot,
  • it is not in a rest zone (the plunger tip, a saucer),
  • no hold key is down (a player cradling the ball on a raised flipper).

Then it nudges the ball up the table, since a ball only stops where something below holds it. The nudges go left, then right, each one grow times harder. If every nudge fails, it says ballSearch.gaveUp and sends giveUpEvent.

It is the second of two defences. PinballTable's trap finder (PinballTable.traps.ts) proves, from the table's geometry, that there is no pocket a ball can settle in. BallSearch covers what geometry cannot see: a ball balanced on an edge, or pinned by a moving part.

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

    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
{
  "entities": {
    "Game": {
      "components": {
        "BallSearch": {
          "restZones": [{ "at": [7.1, 36.5], "radius": 1.2 }],
          "holdKeys": ["ShiftLeft", "ShiftRight"],
          "giveUpEvent": "plunger.serve"
        }
      }
    }
  }
}

Props

  • ballTag (default "ball") — which balls to watch.
  • stillRadius (default 0.15) — a ball that stays this close to one spot is still.
  • stillSeconds (default 2.5) — how long it must be still before a search.
  • restZones — places a ball may sit, each { at: [x, z], radius }.
  • holdKeys — key codes that pause the search while held.
  • nudge (default 8), grow (default 1.5) — the first nudge's speed, and how much harder each next one is.
  • attempts (default 4), interval (default 0.8 s) — nudges per search, and the gap between them.
  • giveUpEvent (default empty) — an event to send when every nudge fails, such as plunger.serve.

Events

  • Emits ballSearch.nudged — { ballId, attempt, at: [x, z], speed }.
  • Emits ballSearch.gaveUp — { ballId, at: [x, z] }.
  • Listens for keyboard.keydown / keyboard.keyup — to know which hold keys are down.

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