How to Simulate Magnetic Repulsion in Matter.js

This article explains how to simulate magnetic repulsion between specific rigid bodies using the Matter.js 2D physics engine. By listening to the engine's update loop, calculating distance vectors between targeted bodies, and applying opposing forces using Coulomb’s Law or inverse-square distance models, you can create realistic repulsive magnetic behaviors.

Core Concept

Matter.js does not contain a native magnetism plugin, but it provides the Matter.Body.applyForce() method and the beforeUpdate engine event. Magnetic repulsion is achieved by:

  1. Identifying pairs of bodies that should repel each other.
  2. Calculating the Euclidean distance and directional vector between them.
  3. Calculating force magnitude inversely proportional to the distance (or distance squared).
  4. Applying equal and opposite forces to push the bodies apart before each physics step.

Implementation Steps

1. Tag Your Magnetic Bodies

Add a custom property or label to identify which bodies should participate in magnetic repulsion.

const bodyA = Matter.Bodies.circle(200, 300, 20, {
    label: 'magnetic',
    magneticCharge: 1
});

const bodyB = Matter.Bodies.circle(260, 300, 20, {
    label: 'magnetic',
    magneticCharge: 1
});

Matter.Composite.add(engine.world, [bodyA, bodyB]);

2. Hook Into the beforeUpdate Event

Attach an event listener to Matter.Events.on(engine, 'beforeUpdate', ...) to compute and apply forces continuously before the engine updates positions.

Matter.Events.on(engine, 'beforeUpdate', () => {
    applyMagneticRepulsion(bodyA, bodyB, 5000);
});

3. Calculate and Apply the Repulsive Force

To avoid extreme physics glitches when bodies overlap (which causes division by zero or massive acceleration), define a minimum interaction distance threshold.

function applyMagneticRepulsion(bodyA, bodyB, strength = 1000) {
    // 1. Calculate delta vector
    const dx = bodyB.position.x - bodyA.position.x;
    const dy = bodyB.position.y - bodyA.position.y;
    
    // 2. Calculate distance
    const distanceSquared = dx * dx + dy * dy;
    const distance = Math.sqrt(distanceSquared);

    // Minimum distance threshold to prevent infinite force
    const minDistance = 30; 
    // Maximum range of the magnetic field
    const maxDistance = 300; 

    if (distance < minDistance || distance > maxDistance) {
        return;
    }

    // 3. Normalized directional vector
    const normalX = dx / distance;
    const normalY = dy / distance;

    // 4. Inverse-square law: Force = strength / distance^2
    const forceMagnitude = strength / distanceSquared;

    const force = {
        x: normalX * forceMagnitude,
        y: normalY * forceMagnitude
    };

    // 5. Apply opposing forces
    // Push bodyA away from bodyB
    Matter.Body.applyForce(bodyA, bodyA.position, {
        x: -force.x,
        y: -force.y
    });

    // Push bodyB away from bodyA
    Matter.Body.applyForce(bodyB, bodyB.position, {
        x: force.x,
        y: force.y
    });
}

Managing Multiple Magnetic Bodies

When managing multiple bodies, iterate through all pairs without duplicating calculations.

const magneticBodies = [/* array of your magnetic bodies */];

Matter.Events.on(engine, 'beforeUpdate', () => {
    for (let i = 0; i < magneticBodies.length; i++) {
        for (let j = i + 1; j < magneticBodies.length; j++) {
            applyMagneticRepulsion(magneticBodies[i], magneticBodies[j], 3000);
        }
    }
});

Stability Tips