Talking about Actionscript 3, Box2D and Flash.
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.
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
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.