stefan s stefan s - 25 days ago 12
iOS Question

What are Sprite Kit's "Category Mask" and "Collision Mask"?

I am following the Sprite Kit guide, and in the scene editor it asks me to set the Category Mask to 32 and Collision Mask to 11. How are these numbers related?

Answer

The Category bit mask tells Sprite-Kit what sort of object this is. The Collision bit mask tells Sprite Kit what objects this object collides with (i.e. will hit and bounce off). The ContactTest bit mask tells Sprite-Kit what contacts you want to be notified about i.e. when this object touches another object.

Collisions are handled automatically by the Sprite-Kit game engine; contacts are handled by your code - when a contact happens that you are interested in, your code (didBeginContact'for Swift 2,'didBegin(contact:) for Swift 3) is called.

You need to think of these in binary and for simplicity, we'll start with simple category bit masks, whereby each object in your scene belongs to only one category.

E.g. in your scene you have a player, a player-missile, an enemy and the screen-edge. We'll assume that the bit masks are 8-bit instead of 32-bit. Think of each number as a range of 8 digits (8 bits) each of which is a 0 or 1.

The objects in your scene have to have unique categories, so we'll assign them as follows:

player.categoryBitMask        = 00000001  (1 in decimal)
playerMissile.categoryBitMask = 00000010  (2 in decimal)
enemy.categoryBitMask         = 00000100  (4 in decimal)
screenEdge.categoryBitMask    = 00001000  (8 in decimal)

If you use numbers that are, in decimal, something other than a power of 2 (1, 2, 4, 8, 16, 32, 65, 128 etc) then more than 1 bit will be set in the category bit mask which complicates things (it means that this object belongs to multiple categories) and your code has to get more complicated.

Now think about what bounces off what (the collisions). Let's say everything bounces off everything else except the missile goes through the screen edge.

The collision bit masks for each object consists of the bits that represent the objects that this object collides with i.e.:

player.collsionBitMask = 00001111  (the bits for all other objects are set)
playerMissile.collisionBitMask = 00000111 (all object EXCEPT screenEdge)
enemy.collisonBitMask = 00001111 (everything)
screenEdge = 00000000 (collides with nothing)

Now we think about which object interactions we are interested in. We want to know when:

  • player and enemy touch
  • enemy and playerMissile touch

This is represented by:

player.contactTestBitMask = 00000100 (the enemy's categoryBitMask)
enemy.contractTestBitMask = 00000011 (the player's categoryBitMask combined with the missile's categoryBitMask))

For your specific example, (Category Mask to 32 and collision mask to 11), the categoryBitMask is 32 which is 00100000 (sticking with only 8 bits). The collisionBitMask is 11, which is 8 + 4 + 1 so in binary this is '00001101' which means it collides with objects with a categoryBitMask of 8, 4 or 1, so I assume that there are objects in your scene with these categoryBitMasks.

By default everything bounces off everything else i.e. the collisionBitMask is all '1's i.e. b'111111..' and nothing notifies of contacts with anything else i.e. contactTestBitMask is all '0's.