How Matter.js Calculates Compound Body Bounds
In Matter.js, the bounds of a compound body are determined by calculating an overall Axis-Aligned Bounding Box (AABB) that encapsulates all of its individual sub-parts. Rather than computing bounds as a single geometric shape, the physics engine updates the world coordinates of every vertex across all constituent parts and evaluates the absolute minimum and maximum X and Y values. This overview explores the internal mechanisms Matter.js uses to track sub-part hierarchies, transform vertices, and dynamically update compound body bounds during simulation steps.
The Anatomy of a Compound Body
A compound body in Matter.js is defined by its parts
array. When you create a compound body using
Body.create({ parts: [...] }), Matter.js sets up a
parent-child relationship:
- Parent Body (
parts[0]): The first element in the array represents the parent body itself, which manages global physical properties such as mass, inertia, position, and velocity. - Child Parts (
parts[1]throughparts[n]): The subsequent elements are the individual physical shapes (rectangles, polygons, or circles) that define the actual geometry and collision boundaries.
Each child body maintains its own set of local vertices, which are defined relative to the compound body's center of mass.
Step-by-Step Calculation of Bounds
Matter.js resolves the outer bounds of a compound body through three main steps:
1. World Coordinate Vertex Transformation
Before calculating bounds, the engine must know where each vertex is
in world space. When a compound body rotates or translates, Matter.js
iterates through each part in body.parts. It applies a 2D
transformation matrix based on the compound body's position and angle to
project the local vertices of each part into world coordinates.
2. Vertex Aggregation
Matter.js aggregates the transformed vertices of the sub-parts. The
parent body's master vertex list is either assigned the combined set of
all sub-part vertices or evaluated across every sub-part sequentially.
For standard collision and broadphase detection, the engine considers
the full collection of vertices belonging to all parts in
body.parts.
3. Axis-Aligned Bounding Box (AABB) Computation
Once the world coordinates of all vertices are established, the
engine utilizes its internal Bounds.update method. The
bounds object consists of two coordinate pairs:
bounds.min: The minimum X and Y values found across all vertices.bounds.max: The maximum X and Y values found across all vertices.
The algorithm loops through every vertex in every part:
// Conceptual representation of the Bounds.update logic
let minX = Infinity, minY = Infinity;
let maxX = -Infinity, maxY = -Infinity;
for (let i = 0; i < vertices.length; i++) {
const vertex = vertices[i];
if (vertex.x < minX) minX = vertex.x;
if (vertex.x > maxX) maxX = vertex.x;
if (vertex.y < minY) minY = vertex.y;
if (vertex.y > maxY) maxY = vertex.y;
}
bounds.min.x = minX;
bounds.min.y = minY;
bounds.max.x = maxX;
bounds.max.y = maxY;The resulting min and max values form the
rectangular boundary aligned with the screen axes (X and Y), fully
containing every part of the compound body regardless of its
orientation.
Dynamic Updates During Simulation
Bounds are not static. During each step of the physics engine
(Engine.update), the following lifecycle occurs for
compound bodies:
- Velocity and Forces Applied: The parent body's position and angle are updated based on velocity, gravity, and external forces.
Body.updateInvocation: The engine updates the positions and vertices of all child parts relative to the parent.- Compound Bounds Refresh: Matter.js re-runs the
bounding box routine across the updated vertices, adjusting
body.boundsto match the new physical footprint.
Purpose of Compound Bounds
Matter.js uses the calculated bounds primarily for the broadphase collision detection stage. Instead of performing expensive Narrowphase SAT (Separating Axis Theorem) checks against every sub-part of a compound body, the engine first checks if the compound body's AABB overlaps with other bodies' AABBs. Only when an overlap occurs does Matter.js proceed to check collisions for the specific sub-parts inside.