Apply Explosive Radial Impulse in Matter.js

This article explains how to simulate an explosive radial impulse in Matter.js that diminishes in strength over distance. Because Matter.js lacks a built-in radial explosion tool, you must iterate over active bodies, determine their proximity to an epicenter, calculate a decaying force vector based on distance, and apply that force using Matter.Body.applyForce.

Step 1: Define the Explosion Parameters

To simulate a blast, establish the epicenter coordinate, the maximum effective blast radius, and the peak force applied to objects at point-blank range.

const blastEpicenter = { x: 400, y: 300 };
const blastRadius = 250;
const blastPower = 0.05; // Matter.js forces are typically small values

Step 2: Query Affected Bodies

Retrieve the list of dynamic bodies in your physics world. You can query every dynamic body in your engine's Composite or use Matter.Query.point or Matter.Query.region to filter bodies within an approximate bounding box before performing distance checks.

const bodies = Matter.Composite.allBodies(engine.world);

Step 3: Calculate Radial Vector and Distance Decay

For each body, find the distance between its center of mass (body.position) and the blast epicenter. If the distance is less than the blast radius and greater than zero, calculate the force decay.

A linear decay model uses a multiplier of 1 - (distance / blastRadius). You can also use an inverse-square model (1 / (distance * distance)) for a sharper drop-off.

function applyRadialImpulse(engine, epicenter, radius, power) {
  const bodies = Matter.Composite.allBodies(engine.world);

  for (let i = 0; i < bodies.length; i++) {
    const body = bodies[i];

    // Ignore static bodies or sensors
    if (body.isStatic || body.isSensor) continue;

    const deltaX = body.position.x - epicenter.x;
    const deltaY = body.position.y - epicenter.y;
    const distance = Math.hypot(deltaX, deltaY);

    // Only apply force within the blast radius
    if (distance > 0 && distance < radius) {
      // Linear falloff: 1 at epicenter, 0 at outer edge
      const decay = 1 - distance / radius;
      
      // Normalize direction vector
      const normalX = deltaX / distance;
      const normalY = deltaY / distance;

      // Scale force by decay factor and mass if uniform acceleration is preferred
      const forceMagnitude = power * decay;
      const force = {
        x: normalX * forceMagnitude,
        y: normalY * forceMagnitude
      };

      // Apply the force at the body's center of mass
      Matter.Body.applyForce(body, body.position, force);
    }
  }
}

Step 4: Applying the Impulse

Matter.js forces are applied per step. Calling applyRadialImpulse on a single update frame acts as an impulse. If you want lighter bodies to travel at the same velocity as heavier bodies, multiply forceMagnitude by body.mass. If you want lighter bodies to be launched further, omit the mass multiplier so that smaller masses experience greater acceleration (\(a = F / m\)).