logo
HighwaySpawner

vehicle · vehicle-combat

HighwaySpawner

1
Unlock

Install with the CLI:

bjs download HighwaySpawner

HighwaySpawner

Decides when a car comes out of a pool onto the road, and when it goes back.

What it does

  • Civilians are a budget: about civilianDensity per 100 m of road ahead, never more than maxCivilians. Each one goes into a free lane, faces up the road and is sent off at its own pace.
  • Police patrol in the traffic. One turns up ahead every policeEvery seconds or so, from level policeFrom. There are never more than maxPolice at once.
  • Enemies come from behind, the way a car grows out of the bottom of the screen. Which kind comes is a weighted pick from the enemies allowed at that level.
  • A car that dies becomes a wreck: its driver lets go, and after wreckSeconds it is cleared.
  • Cars that fall releaseBehind metres behind or run releaseAhead metres ahead go back to their pools.

A car straight out of a pool is standing still. A parked car 150 m ahead is a roadblock, not traffic, so each new car gets a carDrive.nudge that sets it moving. Civilians leave at a speed between civilianSpeedMin and civilianSpeedMax. Enemies leave enemyCatchUp m/s faster than the player, so they close from behind.

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

    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
{
  "Traffic": {
    "components": {
      "HighwaySpawner": {
        "follow": "Player",
        "civilians": ["civilian"],
        "police": ["police"],
        "policeEvery": 22,
        "maxPolice": 2,
        "enemies": [
          { "pool": "rammer", "from": 1, "weight": 3 },
          { "pool": "gunner", "from": 2, "weight": 2 },
          { "pool": "shover", "from": 3, "weight": 1.5 }
        ]
      }
    }
  }
}

Every name in civilians, police and enemies is a Pool. The scene also needs a HighwayRoad; with no road, nothing spawns. Only the first HighwaySpawner in a scene runs.

The civilian budget

Traffic is a count to hold:

TypeScript
export function civilianTarget(windowLength: number, density: number, max: number): number {
  return Math.min(max, Math.round((windowLength / 100) * density));
}

The System passes aheadMax as the window:

text
defaults:         240 m × 1.2 per 100 m = 2.88 → 3 civilians
Endless Rampage:  240 m × 2.1 per 100 m = 5.04 → 5 civilians

When a car is released, the count drops below the target and a new one is placed. Until half the target is out, several can arrive in the same frame; after that, new civilians come 0.35 s apart.

A new car only goes where no car sits within minGap metres along the road in the same lane. An enemy needs only 0.7 of that.

The difficulty curve

TypeScript
    enemyInterval: Math.max(2.5, baseInterval * Math.pow(0.86, l - 1)),
    maxEnemies: Math.min(6, baseMax + Math.floor((l - 1) / 1.5)),
    traffic: Math.min(1.6, 1 + (l - 1) * 0.08),

Each level cuts the gap between enemies by 14%, adds an enemy slot about every one and a half levels, and adds 8% more civilians. With the defaults:

text
level 1:  an enemy every 10.0 s, 1 on the road at once
level 3:  an enemy every  7.4 s, 2 at once
level 5:  an enemy every  5.5 s, 3 at once
level 11: an enemy every  2.5 s (the floor)

Each wait is jittered by ±25%, so the arrivals never feel like a metronome. A director raises the level with highwaySpawner.level.set.

Settings

FieldDefaultWhat it does
follow"Player"The car the traffic is arranged around
spawningtrueSpawn new cars. Range and wreck clean-up run either way.
level1Difficulty level, 1 and up
civilians["civilian"]Pools of civilian cars, picked at random
civilianSpeedMin20Slowest civilian launch speed, m/s
civilianSpeedMax31Fastest civilian launch speed, m/s. Police launch at this speed too.
civilianDensity1.2Civilians per 100 m of the window ahead
maxCivilians10Most civilians at once
enemiesrammer from 1 (weight 3), gunner from 2 (weight 2), shover from 3 (weight 1.5){ pool, from, weight } entries: the pool, the first level it can appear on, and its chance against the others
police[]Pools of police cars. Empty for none.
policeEvery22Seconds between police patrols, give or take 25%
maxPolice2Most police at once
policeFrom1First level police patrol on
enemyInterval10Seconds between enemy arrivals at level 1
maxEnemies1Enemies at once at level 1
enemyCatchUp10How much faster than the player an enemy arrives, m/s
aheadMin110Nearest a civilian or police car appears ahead, metres
aheadMax240Farthest a civilian or police car appears ahead, metres. Also the window the civilian budget counts.
behindMin46Nearest an enemy appears behind, metres
behindMax70Farthest an enemy appears behind, metres
releaseBehind100Cars further than this behind go back to their pool
releaseAhead360Cars further than this ahead go back to their pool
minGap22Clear road a new car needs in its lane, metres
wreckSeconds3Seconds a wreck burns before it is cleared

Events

EventPayloadDirection
highwaySpawner.spawned{ entityId, pool, role, enemy, police }emits
highwaySpawner.released{ entityId, pool, reason }, reason is range, wreck or clearedemits
carDrive.nudge{ entityId, dvx, dvz }emits, to launch each new car
highwaySpawner.level.set{ level }listens
highwaySpawner.enabled.set{ enabled }listens: sets spawning
highwaySpawner.clear{}listens: every car back to its pool for a new game
health.died{ entityId }listens: one of its cars becomes a wreck

Needs

  • Pool holds every car it places.
  • HighwayRoad gives lanes, bridges (it never spawns on one) and road distance.
  • CarDrive marks which entities are cars, gives the player's speed, and takes the nudge.
  • CarCollision lets it skip ghost cars in the gap check.
  • MeshPrimitive gives each car's position and sets a new car's facing.
  • AutoRunnerDriver gives each new car its lane and lets go of a wreck.

More like this

AutoRunnerDirector
AutoRunnerDriver
CarCollision
CarDrive
Health
HighwayRoad
MeshPrimitive
RoadFX
AiDriver
AsteroidField
AutoRunnerBomber
AutoRunnerHUD
AutoRunnerProjectile
AutoRunnerWeapons
BoatMode
BoatWater
CarPaint
ContactDamage
ContactImpulse
DayNightCycle
DeckDealer
EnemySpawner
Headlights
MassDriver
ObstacleField
RoadAudio
RoadCamera
RoadHazard
RoadSpawner
RoadTreadmill
RoadsideScenery
SmokeScreen
SupplyTruck
SurfacePatch
TrafficConvoy
WeaponsVan

Was this page helpful?

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

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search