Update Body Vertices in Real-Time in Matter.js
This guide explains how to dynamically update and mutate the vertices
of a rigid body in Matter.js during runtime. By using the engine's
built-in Body.setVertices method, developers can reshape
bodies, simulate mesh deformations, or create fluid geometric
transformations without completely destroying and recreating physics
instances. The following sections cover the core function, handling
centroid shifts, dealing with concave shapes, and a practical
implementation example.
Using Body.setVertices
The primary way to update a body's geometry in real time is through
the Matter.Body.setVertices utility method. When invoked,
Matter.js replaces the body's vertex array, recalculates its area, mass,
moment of inertia, and updates its axis-aligned bounding box (AABB).
Matter.Body.setVertices(body, newVertices);The newVertices parameter must be an array of
vector-like objects containing x and y
coordinates:
const newVertices = [
{ x: 0, y: 0 },
{ x: 100, y: 0 },
{ x: 100, y: 50 },
{ x: 0, y: 50 }
];Handling the Centroid Offset
A common issue when updating vertices dynamically is the involuntary
movement of the body. Matter.js automatically computes the geometric
center (centroid) of the new vertices and moves the body's
position to that centroid.
To preserve the body's perceived location in world space, store its
original position prior to calling setVertices, or compute
the delta between the old and new centroids and re-apply the desired
position:
// Preserve the current position
const currentPosition = { x: body.position.x, y: body.position.y };
// Apply new vertices
Matter.Body.setVertices(body, newVertices);
// Restore the intended world position
Matter.Body.setPosition(body, currentPosition);Concave Shapes and Poly-Decomp
Matter.js physics calculations require convex polygons. If your
real-time vertex modifications produce a concave polygon, Matter.js will
attempt to decompose the shape into multiple convex parts using the
external poly-decomp library.
- Ensure
poly-decompis loaded in your environment before initializing your engine:Matter.Common.setDecomp(window.decomp); - If
poly-decompis unavailable, Matter.js falls back to using the convex hull of the vertices, ignoring internal angles.
Complete Implementation Example
Below is a complete loop implementation that updates a body's vertices on every engine tick, oscillating a triangle's top vertex back and forth:
const { Engine, Render, Runner, Bodies, Composite, Body } = Matter;
const engine = Engine.create();
const world = engine.world;
const render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
wireframes: false
}
});
// Create an initial triangular body
const dynamicBody = Bodies.fromVertices(400, 300, [
{ x: 0, y: 100 },
{ x: 100, y: 100 },
{ x: 50, y: 0 }
], { isStatic: true });
Composite.add(world, dynamicBody);
Render.run(render);
const runner = Runner.create();
Runner.run(runner, engine);
// Real-time update loop
let angle = 0;
Matter.Events.on(engine, 'beforeUpdate', () => {
angle += 0.05;
const horizontalOffset = Math.sin(angle) * 40;
// Compute updated vertex coordinates relative to the shape
const updatedVertices = [
{ x: 0, y: 100 },
{ x: 100, y: 100 },
{ x: 50 + horizontalOffset, y: 0 } // Move top point dynamically
];
const originalPosition = { x: dynamicBody.position.x, y: dynamicBody.position.y };
// Apply new geometry
Body.setVertices(dynamicBody, updatedVertices);
// Maintain position stability
Body.setPosition(dynamicBody, originalPosition);
});Performance Considerations
Recalculating vertex hulls, mass properties, and decomposition routines is computationally expensive. When updating vertices in real time:
- Keep vertex counts low: Polygons with fewer than 10 vertices perform significantly better in real-time loops.
- Avoid unnecessary concave geometry: Generating dynamic concave shapes every frame can introduce frame-rate drops due to repeated decomposition steps.
- Sleep management: If the body is marked as dynamic, frequent vertex changes will prevent it from sleeping and force the engine to check broadphase collisions continuously.