Box 2D 2.1a Tutorial – Part 5 (Collision filtering)
So the past couple of tutorials we have looked at collisions, in regards to detecting them per body, as well as detecting the exact points of collision. We will continue with the topic of collisions, but this time, we will be specifying filters so we can control which objects collide with which, rather than the default of all objects colliding.
In order to do this, we specify which objects can collide when we create the b2FixtureDef during the b2Body creation phase. The object property we will be dealing with is the b2FilterData property on the b2FixtureDef. There are two main ways for stating which b2Body objects should collide. The first we will look at is the groupIndex.
The group index is of type Integer. We specify an integer which will be the identification of a group that the body belongs to. A b2Body that has had a positive groupIndex set will always collide with other bodies with the same number. If, instead, that b2Body had a negative groupIndex set, then it will never collide with other bodies of the same number. So a positive number is a collision and a negative number is never a collision. Quite simple really.
While useful, what happens when we want multiple rules? For example, A has a negative index of -1, and so does B, as we don’t want them to collide. But then along comes C, who has a negative index of -2, but we also want to ensure that we don’t collide with it.
Category Bits and Mask Bits
This where category bits come in. The category bit is an unsigned integer (so only positive numbers). The difference here is we use the bits of the unsigned integer to represent categories. With an Interger being 16bit means we can specify 16 different categories. Also, unlike with the group index, a b2Body does not have to be part of just 1 group as we can set multiple bits to 1. Once we have specified the category that the body belongs to, then we then set another unsigned Integer, called the category mask, to specify which categories the b2Body will collide with and the wont collide with. A couple of points to take note of.
One important piece of information to note is that the collision pairing must be mutual. By that I mean, if body A has a mask that specifies that it collides with body B, then body B must have a mask that specifies it collides with A, otherwise they will not collide.
The other thing that I have noticed is that by default all bodies belong to category 1. So if you do not explicitly set the category mask, and another b2body has its mask set to 1, then they will collide.
Last, I should mention that the group index can be used in conjunction with category bits. Bear in mind that Group Indexes take precedence over whatever your category bits/masks specify.
So the code to perform filtering will look something like this:
//... other code related to creating the b2Body var chainFixtureDef:b2FixtureDef = new b2FixtureDef(); chainFixtureDef.shape = chainShape; chainFixtureDef.density = 1.0; chainFixtureDef.friction = 0.1; chainFixtureDef.filter.categoryBits = 4; chainFixtureDef.filter.maskBits = 9; _body.CreateFixture(chainFixtureDef);
At the top of the page I have created Box2D demo of a Jellyfish in the ocean and have set up a series of collision rules. There are a few ways I could have set this up, but in this implementation I have done the following.
- The invisible walls have their categoryBits set to 0001 (1)
- The bubbles have their categoryBits set to 0010 (2)
- The Jellyfish head has the categoryBits set to 0100 (4)
- The tentacles (including each segment) is set to 1000 (8)
- Now I want the walls to collide with the Jellyfish head and Jellyfish tentacles. So it’s mask is set to
0100 OR 1000 = 1100 = 12
- The Jellyfish head I want to collide with the walls and with the tentacles so
1000 OR 0001 = 1001 = 9
I then repeat this process so that tentacles collide with the Jellyfish head and walls.
Currently the bubbles collide with nothing, but let’s say that we wanted them to collide with the tentacles. We could follow a similar approach, and specify a mask (1000), so that it collides with the tentacles, and those tentacles collide with the wall, Jellyfish head, and bubbles (1110). Alternatively, we could set the GroupIndex property of the bubbles to 1 and set the GroupIndex property of the tentacles to 1 to achieve the same result.
So that’s about it for filtering. Just watch that binary math, easy to make a small mistake.