[SOLVED] Can someone please point out what i did wrong in my code for detecting collision in cocos2dx?

Setting the bitmaps is the right way to do it - we just need to figure out why its’ not working for you!

So - if the categories are all set to 7 (00000111) then they will all collide with anything that has a collision mask of 1,2,3,4,5,6 or 7 - so now we can see that onContactBegin is being called - so let’s try something else:

First can you simplify it and get rid of the weapon?

Then set player category to 1 and enemy category to 4 (as it is)
Set player mask to 4 and enemy mask to 1

We should still get our OnContactBegin happening

Player category 1 collision bitmask 4, Enemy category 4 bitmask 1.
No onContactBegin called, if i remove the setCategoryBitMask for both, the onContactBegin called.
With or without setCategoryBitMask, player still get contact with enemy (eg being push by enemy when contact), the event just don’t fired.
Btw set bitmask 0x0000001 same as 1 right?

Yes 0x0000001 is the same as 1.

I don’t use the built in physics engine so I’m not sure what is happening here!
The fact that the onContactBegin is being called when you have no category, or when you have category 7 (I guess the ‘no category’ is the equivalent of 11111111 so that kinda makes sense!) means your code is correct for that - but in that case I just can’t see how a collision is happening without that onContactBegin being called.

This may be a dumb question - but you don’t have any other code that could be pushing your player? i.e. you are sure its the physics engine doing the pushing?

Maybe someone who has used the inbuilt physics will chip in - because I’m at a loss to explain the behaviour your seeing!

The enemy will chase the player so the enemy body will try to go to the player’s center, get contacted on player’s physic body hence the pushing, i guest.
What is your way of handle collision, i don’t mind if it’s not use built in fuction, always try to learn something new.

I use physics, but I use Box2d rather than the built in physics .

Oh yeah right, i totally forgot about box2d is in cocos2d too, got to find some tutorial about using box2d in cocos2d. Hope someone find what wrong with my code in the meantime.

The collision bitmask for the enemy is wrong. Collision bitmasks define with which category they collide. However they only collide if they are set in both bodies not just one.

Try this:
enemyBody->setCollisionBitmask(PLAYER_CATEGORY_BITMASK |WEAPON_CATEGORY_BITMASK );

Here is a good tutorial for that btw: http://www.iforce2d.net/b2dtut/collision-filtering

Hi Rambazamba,
I tried your way with just player and enemy collide:
playerBody->setCollisionBitmask(ENEMY_CATEGORY_BITMASK);
enemyBody->setCollisionBitmask(PLAYER_CATEGORY_BITMASK);
with
#define PLAYER_CATEGORY_BITMASK 0x000001
#define ENEMY_CATEGORY_BITMASK 0x000004
And the result still the same, onContactBegin won’t fired on contact.

Ok, thanks guys i am good for now. Just found another tutorial about this and seem to solve my problem. What left for me is to figure it out why use setContactTestBitmask instead of setCollisionBitmask work
enemyBody->setCategoryBitmask(ENEMY_CATEGORY_BITMASK);
enemyBody->setCollisionBitmask(0);
enemyBody->setContactTestBitmask(PLAYER_CATEGORY_BITMASK);

I think people need to understand this to use it properly.

Whenever you create any physics body these three must need to be set setCategoryBitmask, setCollisionBitmask, setContactTestBitmask, if any one is missing without initialize then it will not give you desire outout.
please dont use 'true', 'false' or '0' '1', it will make you difficult to understand.
Also dont set different collision mask for CATEGORY & COLLISION, use single mask per object, like below.

#define COL_MASK_BLANK		0x00000000
#define COL_MASK_PLAYER		0x00000001
#define COL_MASK_WEAPON		0x00000002
#define COL_MASK_ENEMY		0x00000004

Use setCategoryBitmask to set object’s own mask, like below

playerBody->setCategoryBitmask(COL_MASK_PLAYER);
weaponBody->setCategoryBitmask(COL_MASK_WEAPON);
enemyBody->setCategoryBitmask(COL_MASK_ENEMY);

Use setCollisionBitmask for physics response, with which objects you need physics response?
Do you want velocity should change when 2 objects collide? then mention this.
I think in your case, all blank is enough

playerBody->setCollisionBitmask(COL_MASK_BLANK);
weaponBody->setCollisionBitmask(COL_MASK_BLANK);
enemyBody->setCollisionBitmask(COL_MASK_BLANK);

To understand, i will give you another example, suppose there is ball & player which should jump on platform then initialize like below

platformBody->setCollisionBitmask(COL_MASK_BALL + COL_MASK_PLAYER);
playerBody->setCollisionBitmask(COL_MASK_PLATFORM);
ballBody->setCollisionBitmask(COL_MASK_PLATFORM);

Use setContactTestBitmask for listener response, with which objects you need contact listener should be called? onContactBegin etc

playerBody->setCollisionBitmask(COL_MASK_ENEMY);
weaponBody->setCollisionBitmask(COL_MASK_ENEMY);
enemyBody->setCollisionBitmask(COL_MASK_PLAYER + COL_MASK_WEAPON);

So in future if you add new objects then just ‘+’ with old mask values.
I hope this will help you and others as well.
Let me know if you have any doubts.

2 Likes

Mind if I use this in our docs? Super detailed.

Yeah, sure.
Just edit as per your requirement.

Thank you for the detail explanation, i think i got a hang of it now.

Great explanation - just a comment; should not the ‘+’ in the final line really be a ‘&&’?

Thank you.
But that ‘+’ thing is correct.
Like below,
enemyBody->setCollisionBitmask(COL_MASK_PLAYER + COL_MASK_WEAPON + COL_MASK_BULLET);

IN a simple case like you propose, then ‘+’ is fine, as
1 + 2 + 4 == 1 || 2 || 4

But in potentially more complex cases, that doesn’t hold true - e.g.

1 + 3 + 4 != 1 || 3 || 4

( I posted && by mistake - of course I meant ||)

??

Its hex value, it should be power-of-2
Total 8-bit, so total 32 possibilities.

#define COL_MASK_BLANK		0x00000000
#define COL_MASK_PLAYER		0x00000001
#define COL_MASK_WEAPON		0x00000002
#define COL_MASK_ENEMY		0x00000004
#define COL_MASK_WALL	    0x00000008
#define COL_MASK_PLATFORM	0x00000010
#define COL_MASK_BALL		0x00000020
#define COL_MASK_OTHER_1	0x00000040
#define COL_MASK_OTHER_2	0x00000080
#define COL_MASK_OTHER_3	0x00000100
#define COL_MASK_OTHER_4	0x00000200
#define COL_MASK_OTHER_5	0x00000400
#define COL_MASK_OTHER_6	0x00000800

and so on…

The fact is that it does not have to be a power of 2 - in fact it can be useful if it is not - for example I might want to differentiate between platform and wall, but my ‘roof’ needs to act like either.

In that case, wall = 0x08, platform = 0x10 and roof = 0x18 - so anything that collides with the wall or the platform will also collide with the roof.

In this use-case you need to use OR rather than PLUS.

As OR always works and PLUS only works in special cases, one should really use OR all the time.

Also just a small correction - it’s not 8 bit - and if it were and you limited yourself to 1 bit per item, there would only be 8 possibilities! It is 32 bit hence 32 individual possibilities.

ok, let me check by some demo.
I had use in many games but never had any problem.
Also it will be great if any cocos developer give advice here.

No, i didn’t mean that. You can see my above post, how i declare all mask.