logo
By Lawrence

5 minutes

Make a Kill Visible

Every rule of this game now works. A kill still looks like a bug. The fighter you have been chasing for twenty seconds stops existing between one frame and the next, and the only way to be sure you got it is to check a number.

The details were never missing. destroyShip has been emitting spaceshooter.explosion since Course 2, the launcher spaceshooter.missile.fired, the missile spaceshooter.missile.exploded: three events, carrying exact world positions, into a bus with nobody on the other end. This lesson adds the other end.

        "SpaceShooterFX": {}

An explosion is two layers

src/components/SpaceShooterFX/SpaceShooterFX.core.ts
/**
 * The fast, white-hot core of an explosion. `countScale` folds together the
 * component's `density` and, for a player death, its `playerDeathScale`.
 */
export function explosionBurstSpec(
  position: Vec3,
  texture: TextureHandle,
  countScale = 1,
  sizeScale = 1,
): ParticleBurstSpec {
  return {
    position,
    texture,
    count: scaled(3000, countScale),
    emitRadius: 0.12,
    emitRadiusRange: 1,
    minSize: 0.55 * sizeScale,
    maxSize: 2.6 * sizeScale,
    minLifeTime: 0.7,
    maxLifeTime: 1.6,
    minEmitPower: 25,
    maxEmitPower: 130,
    color1: BURST_COLOR_1,
    color2: BURST_COLOR_2,
    colorDead: BURST_COLOR_DEAD,
    blend: 'add',
    gravity: NO_GRAVITY,
    duration: 0.06,
  };
}

Three thousand particles, thrown hard (maxEmitPower 130) from an almost-zero radius, alive for at most 1.6 seconds. That is the flash. It arrives at once, spreads fast, and is gone before you are done reacting to it.

src/components/SpaceShooterFX/SpaceShooterFX.core.ts
/** The slow orange embers that make an explosion read as burning. */
export function explosionEmberSpec(
  position: Vec3,
  texture: TextureHandle,
  countScale = 1,
  sizeScale = 1,
): ParticleBurstSpec {
  return {
    position,
    texture,
    count: scaled(700, countScale),
    emitRadius: 0.35,
    emitRadiusRange: 1,
    minSize: 0.3 * sizeScale,
    maxSize: 0.95 * sizeScale,
    minLifeTime: 1.6,
    maxLifeTime: 3.4,
    minEmitPower: 10,
    maxEmitPower: 55,
    color1: EMBER_COLOR_1,
    color2: EMBER_COLOR_2,
    colorDead: EMBER_COLOR_DEAD,
    blend: 'add',
    gravity: NO_GRAVITY,
    duration: 0.06,
  };
}

Put the two specs side by side and every number moves together. Fewer particles (700 against 3000), smaller (0.95 max against 2.6), thrown gently (55 against 130), and living twice as long (3.4 seconds against 1.6). Both fire at the same instant from the same point.

Continue reading

Unlock the Full Course

Every lesson, the runnable examples, and the finished build — yours to keep.

$9one-time

Was this page helpful?

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

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search