Are you using collision filters in Matter Physics to better control what should or shouldn't collide with each other?
Matter collision filtering can be confusing even though Phaser makes it easier than using the matterjs library directly.
If you are having a hard time understanding groups, categories, and masks or got the collisions to work by trial and error but don't understand why it works then this article is for you!
We will show you how things work with clear examples so that you can apply it confidently!
Collision Groups
First, let's talk about groups. The default value for collisionFilter.group
is 0
. This means that the default behavior is for the collision system to use the category/mask rules.
The practical outcome is that all bodies collide with each other.
Now, let's say we create two MatterSprites
and set the group
to different values:
|
|
Each ship has a different group
value so they should not collide, right?
Nope. 🧐
This may feel unexpected as the docs say:
If the two bodies have the same non-zero value of collisionFilter.group, they will always collide if the value is positive, and they will never collide if the value is negative.
Clearly, we have 2 non-zero positive values that are different: 1 != 2
.
So why are they colliding?
This is where the second half of the rules come in. If the group
values are positive or zero and different from each other then it will use the category/mask rules.
The outcome is the same as having the default group
value of 0
.
We can have the group
values work by setting the collisionFilter.mask
property to 0.
|
|
Now, the two ships will no longer collide with each other. Phaser 3 uses setCollidesWith()
as a more understandable way to set the collisionFilter.mask
property.
You can also directly set the collisionFilter
property of the Matter body like this:
|
|
The key point to remember is that if you want to use groups and ignore the category/mask rules then you need to set the mask
property to 0
. The mask
property is set to -1
by default which means everything will collide with each other.
Collision Category/Mask
The category/mask system is more complicated but also more powerful. It uses a bitmask system and this is where most people get lost.
Phaser will shield you from having to deal with bitmasks as long as you use the setCollidesWith()
method. But if you are trying to read the documentation then very little will make sense without some understanding of bitmasks.
Bitmasks for Simplicity
You may have heard that all computer programs eventually get turned into a series of 1's and 0's. This is the native language of all computers called binary or machine language. We read and write in code but the computer only understands 1 (on) or 0 (off).
All the code we write can be represented in binary including numbers. Binary representaton of numbers looks like this:
0 = 0000
1 = 0001
2 = 0010
4 = 0100
8 = 1000
You'll notice that we are only showing numbers that are a power of 2 from zero to eight. Numbers like 3, 5, 6, or 7 can also be represented but they don't matter for how we'll use bitmasks.
You can have up to 32 collision categories in Matter because of this system where each 1
needs to be by itself in a row of 0
's. This is also known as a 32-bit integer because of the 32 binary spots used to represent numbers. Each spot is technically called a bit. 😎
A bitmask is the combination of these power of 2 numbers. We can use this to check which flags are set depending on which bit is set to 1
.
Let's say you have these 3 collision categories:
|
|
Notice that they are the binary representations of 1, 2, and 4. We can make a mask of category1
and category3
like this:
|
|
The pipe symbol (|
) is the OR bitwise operator meaning that it will combine the two values and set the resulting bit to 1 if there is a 1 at that bit position in either value.
Using this mask
we can check which of the 3 categories are included in a very efficient manner.
That's the basics of bitmasks that you'll need to know to understand what the Matter Physics docs are saying.
Using Categories and Masks
There are 2 key things to understand when using Matter's category/mask rule and they are:
- each Matter body should have a category
- each Matter body mask should include the categories it will collide with
Let's use our ship example again:
|
|
We have a player
and an enemy
and they should collide with each other. Notice that we set the player
category to CATEGORY_PLAYER
and the mask to CATEGORY_ENEMY
with setCollidesWith()
.
Then we do the inverse for the enemy where the category is CATEGORY_ENEMY
and the mask is CATEGORY_PLAYER
.
This satisfies the 2 rules where each body has a category and their mask has the category that they should collide with.
Next, let's say the player shoots lasers and enemies should collide with those:
|
|
You can pass an array of categories to setCollidesWith()
and Phaser will automatically create the appropriate bitmask.
You can also apply your newly learned bitmask knowledge by doing this instead:
|
|
Next Steps
You should now be able to use collision groups, categories, and masks confidently!
Remember that these seemingly complicated computer concepts were designed by other humans and being able to understand them is within your abilities. 🤗 Might just take some work.
Be sure to sign up for our newsletter so you don't miss any future Phaser 3 game development tips and techniques!
Drop your email into the box below.
Don't miss any Phaser 3 game development content
Subscribers get exclusive tips & techniques not found on the blog!
Join our newsletter. It's free. We don't spam. Spamming is for jerks.