I have two different fixed SKPhysicsBody in an SKScene. The only difference between the two is their categoryBitMask. One has a categoryBitMask of 512, the other 1024.
static const u_int32_t kWallCategory = 0x1 << 9; //512
static const u_int32_t kStructureCategory = 0x1 << 10; //1024
In my program, I have a standard contact handler called from -(void)didBeginContact:(SKPhysicsContact *)contact
that begins:
-(void)handleContact:(SKPhysicsContact*)contact {
SKPhysicsBody *bodyA = contact.bodyA;
SKPhysicsBody *bodyB = contact.bodyB;
int type1 = contact.bodyA.categoryBitMask;
int type2 = contact.bodyB.categoryBitMask;
In my program, I need to determine the contact vector between a dynamic body and one of the two fixed bodies. In order to do so, I access the contactNormal property of the SKPhysicsContact
CGVector c = contact.contactNormal;
What I noticed, though, was that the contact vectors were inconsistent and I determined this was because sometimes bodyA of the SKPhysicsContact was the fixed body, sometimes bodyA was the dynamic body.
For example, when a bullet (dynamic body) hits a building (fixed body) from the left, I want the contact vector to be (-1,0)
each time. Currently, the contact vector is sometimes (-1,0)
(from the left) and sometimes (1,0)
(from the right) all depending on which body contact.bodyA
is.
My question: given all else being equal (physics properties, etc.) what determines what is bodyA and what is bodyB in an SKPhysicsContact?
After tinkering with several aspects of each SKPhysicsBody
(mass, friction, categoryBitmask, etc), I've ascertained that the determination between SKPhysicsContact.bodyA
and SKPhysicsContact.bodyB
is based solely on when the SKPhysicsBody is added to the scene
An example to highlight the difference:
SKPhysicsBody *bullet
hits SKPhysicsBody *building
from the left.
Case 1: If *building
was added to the scene before *bullet
, the SKPhysicsContact.contactNormal
is: (-1,0)
Because SKPhysicsContact.bodyA
is *building
, therefore the contact vector is where the *building
is being contacted from (i.e. the left).
Case 2: If *building
was added to the scene after *bullet
, the SKPhysicsContact.contactNormal
is: (1,0)
Because SKPhysicsContact.bodyA
is now *bullet
, therefore the contact vector is where the *bullet
is being contacted from (i.e. the right).
Problem
Because *bullet
and *building
entities are added at various times in my program, I needed to implement a method in which I always knew what SKPhysicsContact.bodyA
and SKPhysicsContact.bodyB
were and, more importantly, a way to keep the SKPhysicsContact.contactNormal
consistent.
Solution
Determine the SKPhysicsBody
that you need to determine where collisions are coming from and set the physicsBody.categoryBitMask
static const u_int32_t kProjectileCategory = 0x1 << 1; //Dynamic body
//Make everything with bitmask > 32 will be set for the fixed bodies
static const u_int32_t kStructureCategory = 0x1 << 10; //Fixed body
Then, in the contact handler:
-(void)handleContact:(SKPhysicsContact*)contact {
//bodyA will be the SKPhysicsBody that was added to the SKScene before bodyB
SKPhysicsBody *bodyA = contact.bodyA;
//bodyB will be the SKPhysicsBody that was added to the SKScene after bodyA
SKPhysicsBody *bodyB = contact.bodyB;
int categoryBitmask1 = contact.bodyA.categoryBitMask;
int categoryBitmask2 = contact.bodyB.categoryBitMask;
CGVector v;
//If the categoryBitmask of bodyA is lower, we will get the contact vector from the Dynamic body, which we don't want
if (categoryBitmask1 < categoryBitmask2)
{
//Since we always want the contact vector determined FROM the fixed body (higher category bitmask), we have to get the reciprocal contact vector in the case that bodyA is the dynamic (non-fixed) body
v = CGVectorMake(contact.contactNormal.dx * -1, contact.contactNormal.dy * -1);
} else {
//If the categoryBitmask
v = contact.contactNormal;
}