Matter.js Composite allBodies Recursive Extraction

This article explains how the Matter.Composite.allBodies function navigates deeply nested scene graphs in Matter.js to retrieve physics bodies. It details the hierarchical tree structure of Matter.js composites, the recursive depth-first traversal mechanism employed by the method, and the performance implications of flattening nested composite structures into a single array.

The Composite Tree Structure in Matter.js

In Matter.js, the scene graph is managed using instances of Matter.Composite. The root scene—usually referenced as engine.world—is itself a top-level composite. A composite serves as an organizational container that can hold three primary collections:

Because a composite can contain other composites, developers can create deeply nested hierarchies, such as representing a ragdoll, a vehicle with wheels, or a multi-part machine as an isolated composite nested inside a larger scene.

The Recursive Extraction Mechanism

Matter.Composite.allBodies(composite) is designed to retrieve every Body within a composite and all of its descendants, returning them as a flat, single-dimensional array.

The function operates using a standard depth-first search (DFS) pattern. When invoked with a target composite:

  1. Initial Collection: The function reads the bodies array directly attached to the current composite and copies them into a working array.
  2. Child Traversal: The function inspects the composites array of the current composite.
  3. Recursive Step: If child composites exist, the function iterates through each child and recursively calls Matter.Composite.allBodies(child).
  4. Flattening and Concatenation: The bodies returned from each recursive call are concatenated into the accumulating array.
  5. Base Case: When a composite has an empty composites array (a leaf node in the tree), no further recursion occurs, and only its direct bodies are returned.

In simplified pseudocode, the logic functions as follows:

Matter.Composite.allBodies = function(composite) {
    let list = [].concat(composite.bodies);

    for (let i = 0; i < composite.composites.length; i++) {
        list = list.concat(Matter.Composite.allBodies(composite.composites[i]));
    }

    return list;
};

Reference Integrity and Duplication

The recursive function extracts references to the original Matter.Body objects; it does not clone or mutate the bodies themselves. Each unique body instance contained within the nested tree structure will appear in the resulting array. However, developers must ensure that cyclic references (e.g., a composite accidentally containing a reference to an ancestor composite) are avoided, as this would cause a stack overflow error during traversal.

Performance and Allocation Considerations

Because Matter.Composite.allBodies creates and concatenates new arrays at every level of recursion, calling it repeatedly inside an active render or update loop (e.g., within requestAnimationFrame or beforeUpdate) incurs continuous memory allocation and garbage collection overhead.

For performance-critical code paths, it is optimal to call this method only when the composite hierarchy has changed (signaled by Matter.js via composite mutation flags) and cache the resulting array rather than re-traversing the tree on every frame.