When I first used box2d I quickly reached the 16 bits limit :-)
Then I found a solution: you don't need to use all 16 bits, you need to categorize your objects.
For example, you have some grounds and solid platforms, you put them in the SOLID category.
You have many enemies, you put them in the ENEMY category.
...
An enemy is an enemy regardless of its abilities like size, speed... You will define those abilities upon creating them. For example:
if g_currentlevel == 1 then
Nme_Flyer.new(xworld, {
posx=xobject.x, posy=xobject.y,
texpath="gfx/playable/Bob.png",
animspeed=14, movespeed=8*0.6, jumpspeed=8*0.5, maxnumjump=2,
density=1, restitution=0.5, friction=0,
BIT=G_BITENEMY, COLBIT=nmecollisions, NAME=G_ENEMY,
lives=1, nrg=1,
})
elseif g_currentlevel == 2 then
Nme_Flyer.new(xworld, {
...
density=2, restitution=1, friction=0,
BIT=G_BITENEMY, COLBIT=nmecollisions, NAME=G_ENEMY,
lives=1, nrg=4,
})
end
My complete set up looks something like this (please note I am using Gideros framework, code is in Lua):
-- here we store all possible objects name -- NO LIMIT
G_GROUND = 2^0
G_MVPLATFORM = 2^1
G_PTPLATFORM = 2^2
G_PLAYER = 2^3
G_PLAYER_BULLET = 2^4
G_ENEMY = 2^5
G_ENEMY_BULLET = 2^6
...
G_LADDER = 2^56 -- ;-)
-- here we define some category BITS (that is those objects can collide) -- 2^15 = MAX
G_BITSOLID = 2^0
G_BITPTPF = 2^1
G_BITPLAYER = 2^2
G_BITPLAYERBULLET = 2^3
G_BITENEMY = 2^4
G_BITENEMYBULLET = 2^5
G_BITSENSOR = 2^6
-- here is another trick (what can collide with what)
solidcollisions = G_BITPLAYER + G_BITPLAYERBULLET + G_BITENEMY + G_BITENEMYBULLET
playercollisions = G_BITSOLID + G_BITPTPF + G_BITENEMY + G_BITENEMYBULLET + G_BITSENSOR
playerbulletcollisions = G_BITSOLID + G_BITENEMY + G_BITENEMYBULLET
nmecollisions = G_BITSOLID + G_BITPTPF + G_BITPLAYER + G_BITPLAYERBULLET + G_BITENEMY
nmebulletcollisions = G_BITSOLID + G_BITPLAYER + G_BITPLAYERBULLET
This way you won't run out of bits :-)
EDIT: added the onBeginContact listener
function LevelX:onBeginContact(e)
local fixtureA, fixtureB = e.fixtureA, e.fixtureB
local bodyA, bodyB = fixtureA:getBody(), fixtureB:getBody()
-- PLAYER1
if (bodyA.name == G_PLAYER and bodyB.name == G_GROUND) or (bodyA.name == G_GROUND and bodyB.name == G_PLAYER) then
if bodyA.name == G_PLAYER then bodyA.numfloorcontacts += 1
else bodyB.numfloorcontacts += 1
end
end
if (bodyA.name == G_PLAYER and bodyB.name == G_LADDER) or (bodyA.name == G_LADDER and bodyB.name == G_PLAYER) then
if bodyA.name == G_PLAYER then bodyA.numladdercontacts += 1
else bodyB.numladdercontacts += 1
end
end
if (bodyA.name == G_PLAYER and bodyB.name == G_PTPLATFORM) or (bodyA.name == G_PTPLATFORM and bodyB.name == G_PLAYER) then
if bodyA.name == G_PLAYER then bodyA.numptpfcontacts += 1
else bodyB.numptpfcontacts += 1
end
end
...