category, mask, group - setFilterData() - why/what?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
gladius2metal
Prole
Posts: 26
Joined: Thu Nov 22, 2012 2:08 am

category, mask, group - setFilterData() - why/what?

Post by gladius2metal »

Groups, categories, and mask can be used to define the collision behaviour of the fixture.

If two fixtures are in the same group they either always collide if the group is positive, or never collide if it's negative. Is the group zero or they do not match, then the contact filter checks if the fixtures select a category of the other fixture with their masks. The fixtures do not collide if that's not the case. If they do have each others categories selected, the return value of the custom contact filter will be used. They always collide if none was set.

There can be up to 16 categories. Categories and masks are encoded as the bits of a 16-bit integer.
https://love2d.org/wiki/Fixture:setFilterData

Can somebody please enlighten me? I guess this triple and the different behaviors make sense, but I can't figure it our right now, so:
1) In what relationship are group, category and mask to each other? Hierarchical? Independent? None at all?
2) Why are there three values?
3) Why these different behaviors? (positive, sameness, etc.)
4) An example (especially for the wiki) would be great :)
User avatar
Boolsheet
Inner party member
Posts: 780
Joined: Wed Dec 29, 2010 4:57 am
Location: Switzerland

Re: category, mask, group - setFilterData() - why/what?

Post by Boolsheet »

gladius2metal wrote:1) In what relationship are group, category and mask to each other? Hierarchical? Independent? None at all?
It's mainly the order that makes them different. Groups are checked first, then the categories. LÖVE implements the default contact filtering behaviour of Box2D and calls the user function only in a certain case. If translated to Lua, LÖVE's contact filtering function looks somewhat like this:

Code: Select all

-- Returns a boolean. True means the fixtures collide, false means no collision.
function internalContactFilter(fixtureA, fixtureB)
	if fixtureA.group ~= 0 and fixtureA.group == fixtureB.group then
		return fixtureA.group > 0
	end

	if bit32.band(fixtureA.categories, fixtureB.mask) == 0 or -- I'm using Lua 5.2's bitwise functions in this example.
	   bit32.band(fixtureB.categories, fixtureA.mask) == 0 then
	   return false
	end

	if type(userContactFilter) == "function" then
		return userContactFilter(fixtureA, fixtureB) -- Set with World:setContactFilter.
	end

	return true
end
This means the user contact filter will only get called if the fixtures have groups that are not equal or zero and the fixtures must have at least one category that the other fixture selects with the mask. (The default for the category is 1 and for the mask it's 0xFFFF, I think)
gladius2metal wrote:2) Why are there three values?
3) Why these different behaviors? (positive, sameness, etc.)
You have to ask the Box2D author why he chose to implement it this way. Comparing and doing bitwise logic on a 16-bit integer is simple and very fast. Perhaps it's a performance thing.
gladius2metal wrote:4) An example (especially for the wiki) would be great :)
I'll try to think of one.
Shallow indentations.
User avatar
gladius2metal
Prole
Posts: 26
Joined: Thu Nov 22, 2012 2:08 am

Re: category, mask, group - setFilterData() - why/what?

Post by gladius2metal »

thx, hmm I think it should be made more explicit that category and mask are used "complementary".
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: category, mask, group - setFilterData() - why/what?

Post by kikito »

A good example I can think about is making a game like Soldat, but with the body of each player being represented with several shapes (arms, legs, head, etc). And with teams, friendly fire and an item that gives immunity for some time.

There are lots of implicit rules there.
  • Each player's arm or leg should not collide with the rest of his body. It should collide with the environment. So probably all the body parts of each player will have its own "group" (they will have a negative group number, so they will not collide with each other at all).
  • There is friendly fire, so projectiles should not impact members of the same team. You can use categories and masks for those. Blue team is category 1, while red team is category 2. The bullets shot by blue team have 1 on their mask, so they "don't hit" people with category 1 (their team), but they hit other guys.
  • There's an immunity item. That could be an special category (say, 3). When a player picks the item, its body gets that category. All bullets from both teams ignore category 3, so they will not hit the player at all.
By the way, if you are going to be using any of this stuff, I suggest you use variables with descriptive names instead of magic numbers. So instead of 1,2,3, create 3 variables called BlueTeamCategory, RedTeamCategory and InvicibleCategory. Otherwise you will get crazy very fast.
When I write def I mean function.
User avatar
gladius2metal
Prole
Posts: 26
Joined: Thu Nov 22, 2012 2:08 am

Re: category, mask, group - setFilterData() - why/what?

Post by gladius2metal »

thx!!!
By the way, if you are going to be using any of this stuff, I suggest you use variables with descriptive names instead of magic numbers. So instead of 1,2,3, create 3 variables called BlueTeamCategory, RedTeamCategory and InvicibleCategory. Otherwise you will get crazy very fast.
I have it already working, after the initial post I just applied the "text" step by step, it is way more "digestable" than it looks ;)
hehe, like COLLISION_GROUP_FIGHTERCRAFT = 1, COLLISION_MASK_FIGHTERCRAFT, COLLISION_CATEGORY_FIGHTERCRAFT, etc.
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 14 guests