logo

Babylon.js Market

SoccerDirector

gameplay

SoccerDirector

1
Unlock

Install with the CLI:

bjs download SoccerDirector

SoccerDirector

The match conductor — the one component that turns a pile of goals into a winnable game of soccer.

What it does

SoccerDirectorSystem is glue. It owns no ball physics, no goal-trigger math, and no per-goal tally routing — those belong to Goal, BallReset, BallPossession, AIZone, and Score. It listens for Goal's goal.scored, reads the scoring net's ownerEntity as the team that scored, and feeds it to a pure deterministic core (createSoccerDirector) that keeps a running score per team, declares a winner once a team reaches matchPoint, and counts total goals.

Because Score already tallies goal.scored and BallReset already re-centres the ball on the same event, the director never touches either — it adds only the match layer. On each goal it broadcasts soccer.scored. If that goal wins the match it emits soccer.matchOver and freezes. Otherwise it queues a framerate-agnostic kickoff: after kickoffDelayMs of accumulated dt it emits possession.reset and aiZone.recenter to hand players and AI back to centre, then soccer.kickoff. An external soccer.matchReset wipes the match and asks Score (score.resetRequest) and Goal (goal.reset) to clear their buckets.

Use it in a scene

Put the director on a singleton world entity. Wire each net's Goal.ownerEntity to the team that scores into it (the ball crossing Blue's net is a point for Red):

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

    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": {
      "SoccerDirector": {
        "matchPoint": 5,
        "kickoffDelayMs": 1500,
        "teams": ["Red", "Blue"]
      }
    }
  }
}

Props

  • matchPoint (number, default 5) — goals a team must reach to win the match.
  • kickoffDelayMs (number, default 1500) — milliseconds of accumulated dt to wait after a non-winning goal before the paced kickoff fires.
  • teams (string[], default ["Red", "Blue"]) — team ids. They seed the scoreboard to 0 and gate which goals count: a goal.scored whose ownerEntity is not one of these teams is ignored.

Events

  • Emits soccer.scored (SoccerDirectorEvents.SCORED) after each goal — { scoringTeam, scores, winner } (winner is null while the match is live).
  • Emits soccer.matchOver (SoccerDirectorEvents.MATCH_OVER) once when a team reaches matchPoint{ winner, scores }.
  • Emits soccer.kickoff (SoccerDirectorEvents.KICKOFF) when the queued restart fires — { scores } — alongside possession.reset (BallPossessionInputEvents.RESET) and aiZone.recenter (AIZoneInputEvents.RECENTER).
  • Listens for goal.scored (GoalEvents.SCORED) — reads ownerEntity as the scoring team.
  • Listens for soccer.matchReset (SoccerDirectorInputEvents.MATCH_RESET) — {} — clears the match and emits score.resetRequest (ScoreInputEvents.RESET) + goal.reset (GoalInputEvents.RESET).

Every name is imported as a constant from its source component — no string literals — so a rename on either end can't silently desync the bus.

Dependencies

Goal (the nets it scores from), Score (the buckets it lets tally), BallReset (re-centres the ball on goal.scored), BallPossession (re-centred on kickoff), and AIZone (the soft zones the AI strikers snap back to on kickoff).

Notes

  • Single match per scene: the System routes events into the first entity carrying a SoccerDirector instance, so author one director.
  • The director never gates the core, so a stuttering net that fires goal.scored twice tallies twice. Keep Goal's cooldown sane to debounce.
  • After a match-ending goal there is no kickoff; the scoreboard stays frozen on the winning state until soccer.matchReset.
  • The director never re-centres the ball — BallReset already did that on goal.scored. It only paces the team/possession/zone restart.

More like this

AIZone
BallPossession
BallReset
Goal
Score
AIGoalSeek
AIKick
BallPursuit
GameConfig
MissionDirector
PlayerInputBridge
PokerBetting
PokerHandEval
PokerMultiplayer
PokerTableDirector
RespawnTimer
Scoreboard
TurnPacer
WaveDirector

Was this page helpful?

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

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search