logo
RoadFX

vehicle · vehicle-combat

RoadFX

1
Unlock

Install with the CLI:

bjs download RoadFX

RoadFX

Blasts, sparks, smoke and dust, all set off by things that already happen in the game.

What it does

RoadFX decides nothing. It listens to the game and draws what each event looks like:

WhenYou see
a car diessmoke, fireball, flash and debris, a scorch on the road, and a fire on the wreck until it is cleared
a missile or bomb burststhe same blast, sized to the burst radius
a bullet or shell hits, or bounces off armoursparks
a missile is fireda smoke trail that follows it
two cars hitsparks, and a camera shake if the player was in it
a car hits a tree, post or housesparks and dust, and a shake if it was the player (a bridge rail gives sparks only)
a car spins outtyre smoke and skid marks while it slides
a car runs onto the grassdirt kicked up behind it
a car goes into the rivera splash
a smoke screen is laida drifting cloud
a wreck is cleareda puff of smoke, and its fire goes out

Anything tagged air, like a helicopter, blows up where it flies, with no scorch and no fire left 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 RoadFX
    bjs download RoadFX

    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
{
  "Game": {
    "tags": ["world"],
    "components": {
      "RoadFX": { "player": "Player", "density": 1 }
    }
  }
}

Put RoadFX on one entity, and call registerRoadFXExtension(adapter) once at bootstrap. Only Babylon has the drawing plugin. Without it the game plays the same, nothing burns, and RoadFX warns once in the console.

Effects as recipes

Every effect is a recipe: a short list of numbers in RoadFX.core. Here is the spark:

TypeScript
  sparks: {
    blend: 'add', sprite: 'spark', count: 14, minSize: 0.1, maxSize: 0.2, endSize: 0.5,
    minLife: 0.15, maxLife: 0.4, minPower: 5, maxPower: 12, radius: 0.15,
    color1: [1, 0.95, 0.7, 1], color2: [1, 0.7, 0.3, 1], colorDead: [0.6, 0.2, 0, 0], gravity: [0, -9, 0], stretched: true,
  },

blend: 'add' makes it glow. Smoke and dust use 'standard', so they hide what is behind them. endSize is how big a bit ends up, as a share of its start size. A gravity of −9 pulls sparks down. Smoke has a small upward one, so it rises.

Bigger blasts

scaled(recipe, k) resizes a recipe for a bigger or smaller event:

TypeScript
    count: Math.max(1, Math.round(r.count * Math.min(3, s * s))),
    minSize: r.minSize * s,
    maxSize: r.maxSize * s,
    minPower: r.minPower * Math.sqrt(s),

Anything tagged shover or helicopter dies at k = 1.4. The fireball goes from 60 bits to 118 (60 × 1.4²). Each bit is 1.4 times as big but flies only 1.18 times as fast. Count grows with area, size with width, and speed only with the square root, so a big blast fills more sky without throwing sparks across the map. The count stops at three times the base.

A missile or bomb burst uses k = radius ÷ 5, and never less than 0.6. Then density multiplies the count, so 0.5 halves every effect.

Draw order

Babylon draws particle systems in the order they were made. A blast makes its smoke before the fireball, so the fire glows through the smoke instead of sitting behind it.

Babylon also throws away a particle system's texture when the system goes. Every effect here shares one sprite, so a spent effect is dropped without its texture. Otherwise the first flash to end would blank every other effect on screen.

Settings

FieldDefaultWhat it does
density1Multiplies every particle count. Use 0.5 on a weak GPU.
explosionShake0.7Camera shake (0 to 1) a blast sends. RoadCamera scales it down with distance from the car it follows.
scorchSeconds18Seconds a scorch mark stays on the road.
player"Player"Entity name of the player's car. A hit or crash on it shakes the camera.

Events

EventPayloadDirection
roadCamera.shake{ trauma, x?, z? }emits
health.died{ entityId }listens
autoRunnerProjectile.exploded{ entityId, owner, kind, x, z, radius, ground }listens
autoRunnerProjectile.hit{ entityId, targetId, owner, kind, x, z, damage }listens
autoRunnerProjectile.ricochet{ entityId, targetId, owner, kind, x, z }listens
autoRunnerProjectile.launched{ entityId, kind, owner, x, z }listens
autoRunnerProjectile.ended{ entityId, kind, x, z, reason }listens
carCollision.hit{ a, b, x, z, closing, dvA, dvB }listens
carCollision.crashed{ entityId, kind, x, z, closing }listens
carCollision.spinout.started{ entityId }listens
carCollision.spinout.ended{ entityId }listens
carCollision.surface.changed{ entityId, surface }listens
carCollision.drowned{ entityId, x, z }listens
roadHazard.laid{ entityId, kind, x, z, radius, life }listens
highwaySpawner.released{ entityId, pool, reason }listens

A hit only throws sparks when closing is 4 m/s or more. Only bullet and shell hits spark. Only kind: "missile" launches get a trail, and only kind: "smoke" hazards get a cloud.

Needs

  • MeshPrimitive: where each car is, so blasts, wreck fires and tyre smoke start in the right place.
  • CarDrive: each car's heading, so skid marks land under the rear wheels.

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