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:
- Category Bits (
categoryBits): A bitmask defining what the fixture is. - Mask Bits (
maskBits): A bitmask defining what the fixture collides with.
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 standardcategoryBitsandmaskBits.
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.