Using Matter.Vector.cross for Torque in Matter.js

This article explains how to determine the rotational force, or torque, generated by an off-center contact in the Matter.js physics engine using Matter.Vector.cross. In two-dimensional physics simulations, when a force is applied anywhere other than an object's center of mass, it induces both linear acceleration and angular acceleration. By computing the 2D cross product of the lever arm vector and the applied force vector, you can extract the exact scalar torque value needed to govern rotational responses.

The Physics of Off-Center Impacts

Rotational force (\(\tau\), or torque) is defined mathematically by the cross product of the displacement vector (\(\mathbf{r}\)) and the force vector (\(\mathbf{F}\)):

\[\tau = \mathbf{r} \times \mathbf{F}\]

In a 2D coordinate system, the cross product between two vectors, \(A(x_1, y_1)\) and \(B(x_2, y_2)\), results in a scalar perpendicular to the 2D plane:

\[\text{cross}(A, B) = (x_1 \cdot y_2) - (y_1 \cdot x_2)\]

A positive result indicates counter-clockwise torque, while a negative result indicates clockwise torque (or vice versa, depending on the coordinate orientation).

How Matter.Vector.cross Works

The Matter.Vector.cross(vectorA, vectorB) function in Matter.js executes this precise 2D scalar formula. It takes two objects containing x and y properties and returns a single numerical value representing the signed magnitude of the cross product.

Step-by-Step Implementation

To calculate the torque from an off-center contact, follow these steps:

  1. Find the Lever Arm Vector: Subtract the body's center of mass position from the contact point position using Matter.Vector.sub.
  2. Obtain the Force Vector: Define or extract the force/impulse vector acting on that contact point.
  3. Compute the Cross Product: Pass the lever arm and the force vector into Matter.Vector.cross.
  4. Apply Torque: Assign or accumulate the resulting scalar directly to the body's torque property, or apply it as angular momentum.

Code Example

// Assume 'body' is a Matter.Body instance
// Assume 'contactPoint' is a {x, y} coordinate where collision/force occurs
// Assume 'force' is a {x, y} vector representing the applied force

// 1. Calculate the lever arm vector (r) from center of mass to contact point
const leverArm = Matter.Vector.sub(contactPoint, body.position);

// 2. Compute the rotational force (torque) using the 2D cross product
const torque = Matter.Vector.cross(leverArm, force);

// 3. Apply the torque to the body
body.torque += torque;

Reading Torque During Collision Events

When handling collision events via Matter.Events.on(engine, 'collisionStart', callback), contact points can be retrieved through the collision pairs.

Matter.Events.on(engine, 'collisionStart', (event) => {
    event.pairs.forEach((pair) => {
        const bodyA = pair.bodyA;
        const bodyB = pair.bodyB;
        
        // Retrieve the first active contact point
        const contact = pair.collision.supports[0];
        if (!contact) return;

        // Lever arms for both colliding bodies
        const rA = Matter.Vector.sub(contact, bodyA.position);
        const rB = Matter.Vector.sub(contact, bodyB.position);

        // Approximate collision normal force
        const normal = pair.collision.normal;
        const impulseMagnitude = pair.collision.penetration; // Used as force proxy
        const contactForce = Matter.Vector.mult(normal, impulseMagnitude);

        // Calculate rotational tendency on both bodies
        const torqueA = Matter.Vector.cross(rA, contactForce);
        const torqueB = Matter.Vector.cross(rB, Matter.Vector.neg(contactForce));
    });
});

Using Matter.Vector.cross directly reveals how much rotational spin an off-center force contributes to a body, providing full control over custom angular dynamics and hit reactions in Matter.js.