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:
- Find the distance vector between their positions: \(\Delta x = x_B - x_A\) and \(\Delta y = y_B - y_A\).
- Calculate the total distance using the Pythagorean theorem: \(d = \sqrt{\Delta x^2 + \Delta y^2}\).
- Normalize the vector (divide \(\Delta x\) and \(\Delta y\) by \(d\)) to create a unit vector representing direction.
- Scale the unit vector by your desired force magnitude.
- 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
- Application Point: Passing
bodyA.positionas the second argument ofBody.applyForceensures the force is applied directly at the center of mass, preventing unwanted torque or rotation. - Mass Scaling: Because acceleration equals force
divided by mass (\(a = F / m\)),
heavier bodies require a larger force magnitude to achieve the same
acceleration. Multiply
forceMagnitudebybodyA.massif you need uniform acceleration across varying body sizes. - Distance Constraints: If simulating real gravity
where force weakens with distance, replace constant scaling with an
inverse-square relationship:
forceMagnitude = G / (distance * distance). Always clamp minimum distance to prevent infinitely large forces when bodies collide.