How to Override Collision Filtering in Planck.js

Planck.js uses a robust filtering system to determine which objects in your 2D physics world should collide and which should pass through each other. While the standard approach relies on category and mask bits, the group index feature provides a powerful shortcut that completely overrides these rules. This article explores how groupIndex functions, how it takes priority over standard filters, and how to implement it effectively in your game or simulation.


Understanding Standard Collision Filtering

In Planck.js (a JavaScript port of Box2D), fixtures use a Filter object to manage collisions. The standard system relies on two main components:

During a collision check, Planck.js performs a bitwise AND operation between one fixture’s categories and the other’s masks. If both checks pass, a collision occurs. While highly flexible, managing dozens of bitmasks can quickly become complex.


How Group Index Overrides the Rules

The groupIndex property is a signed integer that acts as a master override for the category and mask bit logic. When Planck.js evaluates a potential collision between two fixtures, it checks their groupIndex values before looking at any bitmasks.

The override behavior follows two strict rules based on the sign of the matching indices:

1. Positive Group Indices (Always Collide)

If two fixtures share the same positive groupIndex value (e.g., both are set to 1), they will always collide, regardless of what their category and mask bits say. This is incredibly useful for ensuring that parts of a complex object, like a multi-segmented ragdoll or a vehicle, always interact with each other.

2. Negative Group Indices (Never Collide)

If two fixtures share the same negative groupIndex value (e.g., both are set to -1), they will never collide. Their shapes will pass right through each other, ignoring any overlapping bitmasks. A classic use case is a multi-part main character where limbs shouldn’t collide with the torso, or a group of enemy sprites that should pass through one another but still collide with the floor and player.

Note: If the group indices do not match, or if either group index is set to 0 (the default value), Planck.js completely ignores the group index rule and falls back to evaluating the standard categoryBits and maskBits.


Implementing Group Index in Code

To use this feature, you assign the groupIndex to the fixture definition before creating the fixture, or update it dynamically on an existing fixture filter.

// Example: Creating two enemy fixtures that ignore each other
const enemyFilter = {
  groupIndex: -1 // Same negative index means they will never collide
};

// Apply to fixture definitions
const enemyFixtureDef1 = { filter: enemyFilter };
const enemyFixtureDef2 = { filter: enemyFilter };

enemyBody1.createFixture(shape, enemyFixtureDef1);
enemyBody2.createFixture(shape, enemyFixtureDef2);

By leveraging groupIndex, you can bypass complex bitwise math for explicit object groupings, making your collision logic cleaner and easier to maintain.