Introducing Box2D filtering

In Box2D, normally every object collides with other objects in the stage.

But sometimes we may need a way to make an object collide with only certain objects, ignoring the rest. I am not talking about sensors, but real objects that won’t collide with certain other objects.

This feature can be done with filtering.

Collision filtering is a system for preventing collision between shapes. For example, say you make a character that rides a bicycle. You want the bicycle to collide with the terrain and the character to collide with the terrain, but you don’t want the character to collide with the bicycle (because they must overlap). Box2D supports such collision filtering using categories and groups.

Box2D supports 16 collision categories. For each shape you can specify which category it belongs to. You also specify what other categories this shape can collide with. For example, you could specify in a multiplayer game that all players don’t collide with each other and monsters don’t collide with each other, but players and monsters should collide. This is done with masking bits.

The following script is the same we saw a Understanding how Box2D manages boundaries but I am using a random filtering to make the ball ignore the ramp, the wall, or none of them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package {
	import flash.display.Sprite;
	import flash.events.Event;
	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;
	public class bound extends Sprite {
		var body:b2Body;
		public var m_world:b2World;
		public var m_iterations:int=10;
		public var m_timeStep:Number=1.0/30.0;
		var m_boundaryListener=new b2BoundaryListener();
		var bodyDef:b2BodyDef;
		var boxDef:b2PolygonDef;
		var circleDef:b2CircleDef;
		public function bound() {
			addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
			var worldAABB:b2AABB = new b2AABB();
			worldAABB.lowerBound.Set(-100.0, -100.0);
			worldAABB.upperBound.Set(100.0, 100.0);
			var gravity:b2Vec2=new b2Vec2(0.0,10.0);
			var doSleep:Boolean=true;
			m_world=new b2World(worldAABB,gravity,doSleep);
			m_world.SetBoundaryListener(m_boundaryListener);
			// debug draw start
			var m_sprite:Sprite;
			m_sprite = new Sprite();
			addChild(m_sprite);
			var dbgDraw:b2DebugDraw = new b2DebugDraw();
			var dbgSprite:Sprite = new Sprite();
			m_sprite.addChild(dbgSprite);
			dbgDraw.m_sprite=m_sprite;
			dbgDraw.m_drawScale=30;
			dbgDraw.m_alpha=1;
			dbgDraw.m_fillAlpha=0.5;
			dbgDraw.m_lineThickness=1;
			dbgDraw.m_drawFlags=b2DebugDraw.e_shapeBit;
			m_world.SetDebugDraw(dbgDraw);
			// ground
			bodyDef = new b2BodyDef();
			bodyDef.position.Set(4, 12);
			boxDef = new b2PolygonDef();
			boxDef.filter.categoryBits=2;
			boxDef.SetAsOrientedBox(10, 1,new b2Vec2(5, 1.5), Math.PI/32);
			boxDef.friction=0.3;
			boxDef.density=0;
			body=m_world.CreateBody(bodyDef);
			body.CreateShape(boxDef);
			body.SetMassFromShapes();
			// another object
			bodyDef = new b2BodyDef();
			bodyDef.position.Set(8, 12);
			boxDef = new b2PolygonDef();
			boxDef.filter.categoryBits=4;
			boxDef.SetAsBox(1, 3);
			boxDef.friction=0.3;
			boxDef.density=0;
			body=m_world.CreateBody(bodyDef);
			body.CreateShape(boxDef);
			body.SetMassFromShapes();
			// circle
			create_circle();
		}
		public function create_circle() {
			bodyDef = new b2BodyDef();
			bodyDef.position.x=6;
			bodyDef.position.y=2;
			circleDef = new b2CircleDef();
			circleDef.filter.maskBits=Math.ceil(Math.random()*3)*2;
			circleDef.radius=2;
			circleDef.density=1.0;
			circleDef.friction=0.5;
			circleDef.restitution=0.2;
			body=m_world.CreateBody(bodyDef);
			body.CreateShape(circleDef);
			body.SetMassFromShapes();
		}
		public function Update(e:Event):void {
			m_world.Step(m_timeStep, m_iterations);
			if (m_boundaryListener.get_contact()) {
				m_boundaryListener.no_contact();
				m_world.DestroyBody(body);
				bodyDef = new b2BodyDef();
				create_circle();
			}
		}
	}
}

Let’s see the new lines:

Line 44: Assigning the ground object the collision category 2 using filter.categoryBits

Line 55: Assigning the obstacle the collision category 4 using filter.categoryBits

Remember categories must follow the power of two so next group would be 8 and not 5

Line 70: randomly assigning 2, 4 or 6 to ball collision mask using filter.maskBits. When it’s 2, the ball will collide only with objects in category 2, when it’s 4 the ball will collide only with objects in category 4 and when it’s 6 the ball will collide with objects both in category 2 and 4, because 4+2=6.

And this is the result:

Watch the ball changing its behavior according to objects it can collide with.

No need to download source code, just replace the code in Understanding how Box2D manages boundaries

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (7 votes, average: 4.43 out of 5)
Loading ... Loading ...
Flash Templates provided by Template Monster are pre-made web design products developed using Flash technology.
They can be easily customized to meet the unique requirements of your project.
Be my fan on Facebook and follow me on Twitter! Exclusive content for my Facebook fans and Twitter followers

This post has 7 comments

  1. Cataclysm Studios

    on October 2, 2009 at 3:25 pm

    You should really add a play button on your movies, like how Tony Pa does it.

  2. maw

    on October 4, 2009 at 4:06 pm

    Hey, my antivir found a TROJAN (JS.Pakes.bh) on your blog! Be carefully!

  3. pwrtoppl

    on October 10, 2009 at 8:12 am

    interesting stuff about the ability to filter per other objects, box2d is pretty cool

  4. Anthony Sapp

    on December 3, 2010 at 9:35 pm

    The best, most straightforward explanation of this concept I have found. Thanks!

  5. som911

    on October 16, 2011 at 10:08 pm

    how to change maskBit in b2CirlceDef ???

  6. naveen

    on October 25, 2011 at 6:32 am

    really helped a lot in making bodies not to collide certain bodies and collide certain bodies….

  7. CircusMice! A Game in Three Acts « Circus Mice

    on January 29, 2012 at 12:58 am

    [...] called masking. Unfortunately I know nothing about this other than it exists… helpfully Emanuele has a tutorial on it, plus there’s the Box2D manuals and forums. Share [...]