Apply Force Toward Another Body in Matter.js

This article explains how to calculate and apply an attractive or directional force from the center of one physics body toward another using Matter.js. By determining the vector between the two bodies, normalizing it, and applying it with Matter.Body.applyForce, you can easily implement mechanics like gravity, magnetism, or homing behaviors in your physics simulation.

1. The Mathematical Concept

To push or pull bodyA toward bodyB, you must:

  1. Find the distance vector between their positions: \(\Delta x = x_B - x_A\) and \(\Delta y = y_B - y_A\).
  2. Calculate the total distance using the Pythagorean theorem: \(d = \sqrt{\Delta x^2 + \Delta y^2}\).
  3. Normalize the vector (divide \(\Delta x\) and \(\Delta y\) by \(d\)) to create a unit vector representing direction.
  4. Scale the unit vector by your desired force magnitude.
  5. Pass this scaled vector to Matter.Body.applyForce.

2. Implementation Using Matter.Vector

Matter.js provides a built-in Matter.Vector module that simplifies these vector calculations:

const { Body, Vector } = Matter;

function applyForceToward(bodyA, bodyB, forceMagnitude) {
  // 1. Calculate the vector pointing from bodyA to bodyB
  const direction = Vector.sub(bodyB.position, bodyA.position);

  // 2. Find distance to avoid division by zero if bodies overlap
  const distance = Vector.magnitude(direction);
  if (distance === 0) return;

  // 3. Normalize the direction and multiply by the desired force magnitude
  const normalizedDirection = Vector.normalise(direction);
  const force = Vector.mult(normalizedDirection, forceMagnitude);

  // 4. Apply force from the center of bodyA
  Body.applyForce(bodyA, bodyA.position, force);
}

3. Native JavaScript Implementation

If you prefer pure JavaScript without the Matter.Vector utilities:

function applyForceToward(bodyA, bodyB, forceMagnitude) {
  const dx = bodyB.position.x - bodyA.position.x;
  const dy = bodyB.position.y - bodyA.position.y;
  const distance = Math.hypot(dx, dy);

  if (distance === 0) return;

  const force = {
    x: (dx / distance) * forceMagnitude,
    y: (dy / distance) * forceMagnitude
  };

  Matter.Body.applyForce(bodyA, bodyA.position, force);
}

4. Running the Force in the Engine Loop

Forces in Matter.js are instantaneous impulses that decay each step. To maintain a constant pull or dynamic gravitational effect, invoke the function inside the engine's beforeUpdate event listener:

Matter.Events.on(engine, 'beforeUpdate', () => {
  const forceMagnitude = 0.001; // Adjust based on the mass of bodyA
  applyForceToward(bodyA, bodyB, forceMagnitude);
});

Key Considerations