Make a Body Face Its Movement Direction in Matter.js

In Matter.js, rigid bodies do not automatically align their rotation with their trajectory. To make a body point toward the direction it travels, you must read its current velocity vector, compute the angle of movement using trigonometry, and update the body's angle property inside the simulation update loop. This guide outlines the mathematical concept and provides a practical implementation for aligning any Matter.js body with its direction of motion.

The Mathematics Behind Trajectory Orientation

A moving body in Matter.js has a velocity vector represented by body.velocity.x and body.velocity.y. To find the directional angle of this vector in radians, use the standard arctangent function:

\[\theta = \text{atan2}(v_y, v_x)\]

In JavaScript, this is calculated via Math.atan2(body.velocity.y, body.velocity.x).

Implementation Steps

  1. Listen for Engine Updates: Hook into the engine's beforeUpdate event so rotation is updated before the next frame is rendered.
  2. Check for Significant Movement: Avoid recalculating the angle when the body is nearly stationary, which prevents jittering or resetting the angle to zero when velocity drops to zero.
  3. Set the Angle: Use Matter.Body.setAngle() to update the body's orientation.

Code Example

Here is a complete implementation demonstrating how to orient a body along its path:

const { Engine, Render, Runner, Bodies, Composite, Events, Body } = Matter;

// Create engine and world
const engine = Engine.create();
const world = engine.world;

// Create a render
const render = Render.create({
  element: document.body,
  engine: engine,
  options: {
    width: 800,
    height: 600,
    wireframes: false
  }
});

Render.run(render);
const runner = Runner.create();
Runner.run(runner, engine);

// Create an elongated body (like an arrow or missile)
const arrow = Bodies.rectangle(100, 300, 60, 15, {
  frictionAir: 0.01
});

Composite.add(world, arrow);

// Apply an initial velocity
Body.setVelocity(arrow, { x: 10, y: -8 });

// Minimum speed threshold to prevent jitter when nearly still
const SPEED_THRESHOLD = 0.1;

// Update the angle before each physics step
Events.on(engine, 'beforeUpdate', () => {
  const vx = arrow.velocity.x;
  const vy = arrow.velocity.y;
  const speed = Math.hypot(vx, vy);

  if (speed > SPEED_THRESHOLD) {
    const angle = Math.atan2(vy, vx);
    Body.setAngle(arrow, angle);
  }
});

Important Considerations