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
- Listen for Engine Updates: Hook into the engine's
beforeUpdateevent so rotation is updated before the next frame is rendered. - 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.
- 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
- Initial Asset Orientation:
Math.atan2treats an angle of0as pointing directly along the positive X-axis (to the right). Ensure that your body shape or sprite texture natively points to the right so the visual aligns with the calculated angle. - Angular Velocity Conflicts: Manually setting the
angle via
Body.setAngle()overrides the body's physics-driven rotation. If you want the body to retain realistic collisions, ensure you manage or resetbody.angularVelocityto zero to avoid erratic rotational behavior.