Merging Craters into a Matter.js Landscape
Matter.js does not provide native constructive solid geometry (CSG) or polygon clipping tools, making dynamic terrain modification require an external geometry pipeline. This article details how to approximate circular craters as polygons, merge overlapping craters using a 2D boolean clipping library, subtract them from a static landscape, and reconstruct the updated rigid body in Matter.js using vertex decomposition.
1. Representing Terrain and Craters as Polygons
To alter a terrain polygon in Matter.js, the terrain and the circular
craters must be represented as discrete lists of 2D coordinates
({x, y}). Since true circles cannot be processed by
standard 2D polygon-clipping algorithms, approximate each crater circle
using regular polygon vertices:
function createCirclePolygon(centerX, centerY, radius, segments = 16) {
const vertices = [];
for (let i = 0; i < segments; i++) {
const angle = (i / segments) * Math.PI * 2;
vertices.push({
x: centerX + radius * Math.cos(angle),
y: centerY + radius * Math.sin(angle)
});
}
return vertices;
}2. Performing Boolean Operations with a Clipping Library
Matter.js relies on static vertex lists and cannot subtract shapes on its own. Use an external polygon-clipping library such as ClipperLib (Javascript port of Angus Johnson's Clipper) or PolyBool.js to perform the geometric operations.
When multiple craters overlap:
- Union overlapping craters: If craters are generated
concurrently, combine them into a unified polygon mask using a
Boolean Unionoperation. - Subtract from the terrain: Subtract the crater
polygon(s) from the base landscape polygon using a
Boolean Differenceoperation.
Using ClipperLib terminology:
- Set the terrain polygon as the Subject.
- Set the crater polygon (or combined craters) as the Clip.
- Execute a
ClipType.ctDifferenceoperation with the fill rule set toPolyFillType.pftNonZero.
This operation returns an array of one or more non-intersecting polygons, accounting for scenarios where an explosion splits the landscape into multiple distinct landmasses.
3. Decomposing and Updating Matter.js Bodies
Matter.js bodies must be convex. When you modify terrain, the
resulting polygon is almost always concave. Matter.js automatically
handles concave polygons via its internal integration of
poly-decomp.js, which breaks complex polygons into an array
of convex parts.
Ensure poly-decomp.js is loaded into your execution
environment before creating the bodies:
// Ensure poly-decomp is available to Matter.js
Matter.Common.setDecomp(decomp);
function updateTerrainBody(world, oldBody, newPolygonVertices) {
// 1. Remove the old terrain body from the physics world
Matter.Composite.remove(world, oldBody);
// 2. Generate a new composite or multi-convex body from the clipped vertices
// Note: fromVertices calculates the center of mass automatically
const newBody = Matter.Bodies.fromVertices(
0,
0,
newPolygonVertices,
{
isStatic: true,
render: {
fillStyle: '#555555',
strokeStyle: '#222222',
lineWidth: 1
}
},
true
);
// Reposition the body if offsets shifted during decomposition
Matter.Body.setPosition(newBody, {
x: newBody.bounds.min.x + (newBody.bounds.max.x - newBody.bounds.min.x) / 2,
y: newBody.bounds.min.y + (newBody.bounds.max.y - newBody.bounds.min.y) / 2
});
// 3. Add the new body back to the physics simulation
Matter.Composite.add(world, newBody);
return newBody;
}4. Performance Considerations
Regenerating concave collision geometry is computationally heavy:
- Limit Crater Vertices: Using 12 to 16 vertices per crater provides a sufficient circular illusion while drastically reducing decomposition time.
- Batch Modifiers: If several craters occur in the same frame (such as shotgun blasts or cluster bombs), union all craters together first and perform only a single difference operation and body reconstruction step.
- Subdivide Static Terrain: Instead of one massive world polygon, partition the map into multiple contiguous vertical or grid-based chunks. Only recalculate and re-instantiate the chunk that directly intersects the bounding box of the crater.