Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
A little information about Collision Filters — Gideros Forum

A little information about Collision Filters

twisttaptwisttap Member
edited May 2012 in General questions
Hello Everybody :)

I am posting the fallowing stuff about the Collision Filters as I didnt see an example yet. I hope this little tutorial can assist other members of this great community :)

1. What is a Collision Filter ?
Simply, collision filters are filters that determine which objects can interact with each other (collide) and which objects can not.

2. I want to see an example ?
You want an example, so here we go :) I will take Pac-Man as an example for this little tutorial. IF we list the objects in the Pac-Man game, we have Pac-Man, Enemies, Points to collect and Fruits (For Bonus Points). Lets First assign some numbers to our assets to identify them and lets make those numbers powers of 2.
I will say PacMan(1), Enemy(2), Points(4), Fruits(8). If you remember the game, PacMan can eat points, fruits and also can be killed by enemy. So all assets can interact with PacMan, means I can write this like:

categoryBits = sum of maskBits ->
PacMan(1) = Enemy(2) + Points(4) + Fruits(8)
so
PacMan(1) = 14
we can write this as:
PacManFilterData = {categoryBits = 1, maskBits = 14, groupIndex = 0}



If PacMan can interact with all those other assets, this means also all of those can interact back with PacMan so we should also write filterData or them.
Enemy allowed to only kill PacMan and can not interact with other assets so:
Enemy(2) = PacMan(1)
EnemyFilterData = {categoryBits = 2, maskBits = 1}

For Points and Fruits, they can interact only with PacMan
Points(4) = PacMan(1)
PointsFilterData = {categoryBits = 4, maskBits = 1}

Fruits(8) = PacMan(1)
FruitsFilterData = {categoryBits = 8, maskBits = 1}

later on you can declare this for your fixture like:

local PacManFixture = PacMan:createFixture{shape = pacman, density=1.0, friction = 1.0, resitution = 0.5}
PacManFixture:setFilterData(PacManFilterData)


IMPORTANT !

- categoryBits and maskBits must be powers of 2.
- I do now know the limit but I tried up to 64 and it works fine and I am sure limit is much more higher then that.
- Never Ever forget to match maskBits and categoryBits. Interaction happens in two way, so if you are writing a filter for ObjectA you must also write for ObjectB.
- I added a crap sample, enjoy (Red Box can touch everyother objects while black and blue can not )
just copy and paste the code and run it.
- Its 05:45 here so sorry for spelling mistakes etc. :)

Tolga
 
-- Modified code from AppCodingEasy
require "box2d"
 
scene = Core.class(Sprite)
 
function scene:init()
 
	self.world = b2.World.new(0, 9.8, true)
 
	local screenW = application:getContentWidth()
	local screenH = application:getContentHeight()
 
	self:wall(0,screenH/2,10, screenH)
	self:wall(screenW/2,0,screenW,10)
	self:wall(screenW,screenH/2,10,screenH)
	self:wall(screenW/2,screenH,screenW,10)
 
 
	self.boxa = self:createBox(150,150,"red")
	self.boxb = self:createBox(250,250,"blue")
	self.boxc = self:createBox(10,15,"black")
 
 
	local ground = self.world:createBody({})
 
 
	local mouseJoint = nil
 
 
	function self:onMouseDown(event)
		if self.boxa:hitTestPoint(event.x, event.y) then
			local jointDef = b2.createMouseJointDef(ground, self.boxa.body, event.x, event.y, 100000)
			mouseJoint = self.world:createJoint(jointDef)
		elseif self.boxb:hitTestPoint(event.x, event.y) then
			local jointDef = b2.createMouseJointDef(ground, self.boxb.body, event.x, event.y, 100000)
			mouseJoint = self.world:createJoint(jointDef)
		elseif self.boxc:hitTestPoint(event.x, event.y) then
			local jointDef = b2.createMouseJointDef(ground, self.boxc.body, event.x, event.y, 100000)
			mouseJoint = self.world:createJoint(jointDef)
		end
	end
 
 
	function self:onMouseMove(event)
		if mouseJoint ~= nil then
			mouseJoint:setTarget(event.x, event.y)
		end
	end
 
 
	function self:onMouseUp(event)
		if mouseJoint ~= nil then
			self.world:destroyJoint(mouseJoint)
			mouseJoint = nil
		end
	end
 
	self:addEventListener(Event.MOUSE_DOWN, self.onMouseDown, self)
	self:addEventListener(Event.MOUSE_MOVE, self.onMouseMove, self)
	self:addEventListener(Event.MOUSE_UP, self.onMouseUp, self)
 
 
 
	--local debugDraw = b2.DebugDraw.new(false)
	--self.world:setDebugDraw(debugDraw)
	--self:addChild(debugDraw)
 
 
	self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
 
 
 
 
 
end
 
 
 
 
 
 
function scene:wall(x, y, width, height)
 
local wall = Shape.new()
 
	wall:setFillStyle(Shape.SOLID, 0xff0000) 
	wall:beginPath()
 
 
	wall:moveTo(-width/2,-height/2)
	wall:lineTo(width/2, -height/2)
	wall:lineTo(width/2, height/2)
	wall:lineTo(-width/2, height/2)
	wall:closePath()
	wall:endPath()
	wall:setPosition(x,y)
 
 
	local body = self.world:createBody{type = b2.STATIC_BODY}
	body:setPosition(wall:getX(), wall:getY())
	body:setAngle(wall:getRotation() * math.pi/180)
	local poly = b2.PolygonShape.new()
	poly:setAsBox(wall:getWidth()/2, wall:getHeight()/2)
	local fixture = body:createFixture{shape = poly, density = 1.0, 
	friction = 0.1, restitution = 0.8}
 
	wall.body = body
	wall.body.type = "wall"
 
 
	local body = self.world:createBody{type = b2.STATIC_BODY}
	body:setPosition(wall:getX(), wall:getY())
	body:setAngle(wall:getRotation() * math.pi/180)
	local poly = b2.PolygonShape.new()
	poly:setAsBox(wall:getWidth()/2, wall:getHeight()/2)
 
	---------------------------------- Filter Stuff ---------------------------------
	local fixture = body:createFixture{shape = poly, density = 1.0, friction = 0.1, restitution = 0.8}
	fixture:setFilterData({categoryBits = 8, maskBits = 7, groupIndex = 0})
	---------------------------------------------------------------------------------
 
	wall.body = body
	wall.body.type = "wall"
 
 
	self:addChild(wall)
 
 
	return wall
 
end
 
 
 
 
 
 
 
 
function scene:createBox(x, y, color)
 
local block = Shape.new()
 
if color == "red" then
print("Red")
block:setFillStyle(Shape.SOLID, 0xff0000)  
 filterData = {categoryBits = 1, maskBits = 14, groupIndex = 0}
 
elseif color == "blue" then
print("Blue")
block:setFillStyle(Shape.SOLID, 0x00ff)  
 filterData = {categoryBits = 2, maskBits = 1, groupIndex = 0}
else
print("Black")
block:setFillStyle(Shape.SOLID, 0x000000)
 filterData = {categoryBits = 4, maskBits = 1, groupIndex = 0}
end
 
block:beginPath(Shape.NON_ZERO)
block:moveTo(0, 0)
	block:lineTo(50, 0)
	block:lineTo(50, 50)
	block:lineTo(0, 50)
	block:lineTo(0, 0)
	block:endPath()	
	x = y - 10
	y = y -10
 
block:setPosition(x,y)
 
 
local myBody = self.world:createBody{type = b2.DYNAMIC_BODY}
myBody:setPosition(block:getX(), block:getY())
myBody:setAngle(block:getRotation() * math.pi/180)
 
local poly = b2.PolygonShape.new()
	poly:setAsBox(block:getWidth()/2, block:getHeight()/2, 25, 25, 0)
	local fixture = myBody:createFixture{shape = poly, density = 0.1, friction = 1.0, restitution = 0.01}
	fixture:setFilterData(filterData)
 
	block.body = myBody
	block.body.type = "block"
print(block.body.type)
self:addChild(block)
 
return block
 
 
 
 
end
 
function scene:onEnterFrame() 
	self.world:step(1/60, 8, 3)
	for i = 1, self:getNumChildren() do
 
		local sprite = self:getChildAt(i)
 
		if sprite.body then
 
			local body = sprite.body
 
			local bodyX, bodyY = body:getPosition()
 
			sprite:setPosition(bodyX, bodyY)
 
			sprite:setRotation(body:getAngle() * 180 / math.pi)
		end
	end
end
 
 
 
local mainScene = scene.new()
stage:addChild(mainScene)
+1 -1 (+4 / -2 )Share on Facebook

Comments

  • ar2rsawseenar2rsawseen Maintainer
    edited May 2012
    Hey,
    great tutorial, thanks.

    BTW you can put your code inside
    <pre lang="lua">
    </pre>
    to mark it up
  • evsevs Member
    Thanks for the tutorial, really clear and perfect timing for my adventures in box2d =D>


    cheers

    evs
  • gorkemgorkem Maintainer
    It's wonderful when someone asks a single question, and then comes up with complete example that would help every dev out there <:-P
  • @twisttap: Box2D collision filters allow for 16 different categories (colliding object types) so bit values between 1 (2 ^ 0) and 32768 (2 ^ 15) can be used for categoryBits & maskBits. Of course, this limits you to a maximum of 16 different categories of object but I've not heard anybody ever complain that this is not enough. This information and more can be found here :)

    n.b. The ^ above means to the power of so 2 ^ 4 would be 2 to the power of 4 or (2 x 2 x 2 x 2) = 16
  • Great tutorial, but can you please explain what the group index part does?

    Thanks
  • @Tom2012: If you follow the link I provided in my post above and scroll down about a page, you will see the section on filtering which includes the definition/use of the group index.
  • Hi..
    As it is mentioned above
    - categoryBits and maskBits must be powers of 2.

    But, I got confused after reading
    ---------------------------------- Filter Stuff ---------------------------------
    	local fixture = body:createFixture{shape = poly, density = 1.0, friction = 0.1, restitution = 0.8}
    	fixture:setFilterData({categoryBits = 8, maskBits = 7, groupIndex = 0})
    	---------------------------------------------------------------------------------
    Here maskBits = 7; which is not powers of 2. This example works fine, but I want to know how do we decide maskBits?
    categoryBits are fine and all are powers of 2...

    I'm getting confused for how to set maskBits..
    As I've set categoryBits for all my objects as follows:
    1, 2, 4, 8 and 16 but what about maskBits?????
  • ar2rsawseenar2rsawseen Maintainer
    edited September 2013
    categoryBits are unique identification of your own box2d body type and it must be in power of 2.
    maskBits is the sum of all other categoryBits with which your box2d body should collide., if you make it collide with bodies which has categoryBits of 1, 2 and 4, as the result (sum of all category bits) you will have maskBits 7.

    Hope that helps ;)
  • For me it usually helps to create a collision dependency table, to calculate the maskbits.
    Something like this:
    image
    collisionTable.jpg
    574 x 143 - 53K
  • Thank you @ar2rsawseen, Now I understood and cleared my confusion...
    :)
  • this is what i do
     
    wall_categoryBit = 1
    		box_categoryBit = 2
    		circle_categoryBit = 4
     
    		wall_maskBit = wall_categoryBit + box_categoryBit + circle_categoryBit
    		box_maskBit = wall_categoryBit + box_categoryBit 
    		circle_maskBit = wall_categoryBit + circle_categoryBit
    +1 -1 (+2 / -0 )Share on Facebook
Sign In or Register to comment.