2

So I'm learning how to check bitmask collisions in Swift and I'm confused about whether or not to set both bodies to have each other's contact bitmask.

My confusion comes from the following in the docs:

When two physics bodies overlap, a contact may occur. SceneKit compares the body’s contact mask to the other body’s category mask by performing a bitwise AND operation. If the result is a nonzero value, SceneKit creates an SCNPhysicsContact object describing the contact and sends messages to the contactDelegate object of the scene’s physics world.

From what I understand, collisions do not need to be reciprocal - in other words, one can collide with another and the other stays without motion. Please correct me if I'm wrong. But when it comes to contact testing, if A has its category mask set to 1 and contact bitmask set to 2, and B has its category mask set to 2 and its contact bitmask set to 4, then will A and B colliding register as a contact? What if B sets its contact bitmask to 1 now? Will two collisions register?

Ramkrishna Sharma
  • 6,961
  • 3
  • 42
  • 51
rb612
  • 5,280
  • 3
  • 30
  • 68

1 Answers1

2

Let me try to explain all these bit masks with an example from an actual game code. This game has the following objects: ball, pitch, ground, bat, boundary, batting stumps, bowling stumps which will have physics interactions.

Sorry the code is in ObjC, but translation to Swift is straightforward.

Step 1: Set up the category bit masks, which specify the type of each object


typedef NS_OPTIONS(NSUInteger, CollisionCategory) {
  CollisionCategoryBall = 1 << 1,
  CollisionCategoryPitch = 1 << 2,
  CollisionCategoryGround = 1 << 3,
  CollisionCategoryBat = 1 << 4,
  CollisionCategoryBoundary = 1 << 5,
  CollisionCategoryBattingStumps = 1 << 6,
  CollisionCategoryBowlingStumps = 1 << 7,
};

Step 2: Now we decide which objects have collisions with each other.


For example for the ball object, there are collisions with pitch, ground bat and boundary. This is setup as follows, a bitwise OR operation, assuming ballBody is a SCNPhysicsBody:

ballBody.collisionBitMask =
      (CollisionCategoryPitch | CollisionCategoryGround | CollisionCategoryBat |
       CollisionCategoryBoundary);

Step 3: (Optionally), if you want to be notified when two physics bodies are in contact with each other.


Here, you set up the contactTestBitMask. For the ball for example, I want to be notified when it is in contact with pitch, ground, bat, boundary. Again, to do that:

ballBody.contactTestBitMask =
      (CollisionCategoryPitch | CollisionCategoryGround | CollisionCategoryBat |
       CollisionCategoryBoundary);

When you set up the contactTestBitMask, you will handle the contact notifications in the physics delegate, which will be something like this:

- (void)physicsWorld:(SCNPhysicsWorld*)world
     didBeginContact:(SCNPhysicsContact*)contact {
  CollisionCategory contactMask = contact.nodeA.physicsBody.categoryBitMask |
                                  contact.nodeB.physicsBody.categoryBitMask;
  if ((contactMask == (CollisionCategoryBall | CollisionCategoryPitch)) &&
      !self.ballLandedOnPitch) {
    NSLog(@" Ball hit the pitch");
  }
  ...
}

So overall you just categorize your objects, then setup the collision mask which is just a bitwise OR operation of the category masks of the objects with which there will be collisions and optionally to handle the contacts of bodies with each other, set up the contact test bit mask.

But when it comes to contact testing, if A has its category mask set to 1 and contact bitmask set to 2,

I am not sure if you intend to explicitly set the contact bit mask to 2 above; the contact mask should be really be a bitwise OR operation of the category masks of the objects with which there will be contacts and you want to be notified of.

I think the docs are a bit confusing and hope the above explanation clears up your doubts.

3d-indiana-jones
  • 879
  • 7
  • 17
  • Thank you so much!! I really appreciate the explanation and I do believe this clears up a few of my thoughts. I do have a few questions though: do category masks have to be set up as a bit shift of one? In other words, can a category be composed of more than one / all bits set to 1? Like a category bitmask of 1111111. And also, because a collision involves two objects, does only one need to have the other set as its contact mask in order to be notified? Or do they need to have contact masks set to each other? I have read that it is one or the other, but I'm not quite sure. – rb612 Dec 28 '16 at 05:27
  • `Like a category bitmask of 1111111`? Yes, that is possible, see: https://developer.apple.com/reference/scenekit/scnphysicsbody/1514768-categorybitmask. `do they need to have contact masks set to each other`?just setting one or the other will suffice. – 3d-indiana-jones Dec 28 '16 at 05:41
  • ah so in terms of categories, there can only be 8, but an object can belong to multiple categories, is that right? – rb612 Dec 28 '16 at 05:42
  • As the bit mask is `Int`, that should be 32 or 64 categories based on the size of the platform. http://stackoverflow.com/questions/27440100/what-is-the-difference-between-int-and-int32-in-swift. – 3d-indiana-jones Dec 28 '16 at 06:28