How to define category bit mask enumeration for SpriteKit in Swift?

16,943

Solution 1

What you could do is use the binary literals: 0b1, 0b10, 0b100, etc.

However, in Swift you cannot bitwise-OR enums, so there is really no point in using bitmasks in enums. Check out this question for a replacement for NS_OPTION.

Solution 2

If you look at this swift tutorial, you can avoid the whole toRaw() or rawValue conversion by using:

struct PhysicsCategory {
  static let None      : UInt32 = 0
  static let All       : UInt32 = UInt32.max
  static let Monster   : UInt32 = 0b1       // 1
  static let Projectile: UInt32 = 0b10      // 2
}

monster.physicsBody?.categoryBitMask = PhysicsCategory.Monster 
monster.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile 
monster.physicsBody?.collisionBitMask = PhysicsCategory.None 

Solution 3

Take a look at the AdvertureBuilding SpriteKit game. They rebuilt it in Swift and you can download the source on the iOS8 dev site.

They are using the following method of creating an enum:

enum ColliderType: UInt32 {
  case Hero = 1
  case GoblinOrBoss = 2
  case Projectile = 4
  case Wall = 8
  case Cave = 16
}

And the setup is like this

physicsBody.categoryBitMask = ColliderType.Cave.toRaw()
physicsBody.collisionBitMask = ColliderType.Projectile.toRaw() | ColliderType.Hero.toRaw()
physicsBody.contactTestBitMask = ColliderType.Projectile.toRaw()

And check like this:

func didBeginContact(contact: SKPhysicsContact) {

// Check for Projectile
    if contact.bodyA.categoryBitMask & 4 > 0 || contact.bodyB.categoryBitMask & 4 > 0   {
          let projectile = (contact.bodyA.categoryBitMask & 4) > 0 ? contact.bodyA.node : contact.bodyB.node
    }
}

Solution 4

As noted by, user949350 you can use literal values instead. But what he forgot to point out is that your raw value should be in "squares". Notice how the sample of code of Apple enumerates the categories. They are 1, 2, 4, 8 and 16, instead of the usual 1, 2, 3, 4 , 5 etc.

So in your code it should be something like this:

enum CollisionCategory:UInt32 {
case PlayerSpaceShip = 1,
case EnemySpaceShip = 2,
case ChickenSpaceShip = 4,

}

And if you want your player node to collide with either enemy or chicken spaceship, for example, you can do something like this:

playerNode.physicsBody.collisionBitMask = CollisionCategory.EnemySpaceShip.toRaw() | CollisionCategory.ChickenSpaceShip.toRaw()

Solution 5

Try casting your cases as UInt.

enum CollisionCategory: UInt{
    case PlayerSpaceship = 0
    case EnemySpaceship = UInt(1 << 0)
    case PlayerMissile = UInt(1 << 1)
    case EnemyMissile = UInt(1 << 2)
}

This gets rid of the errors for me.

Share:
16,943
Rafał Sroka
Author by

Rafał Sroka

sSSSs SSSSSSS SSSSSSS SSSSS .--' '--. / \ / | | \ / / \ : / \ \ ( ( ) : ( ) ) \ \ / \ / / _`\/ . \/`_____ /~~; ;~~~~~/| / '.__|__.' _/ /__________________/ | |

Updated on July 16, 2022

Comments

  • Rafał Sroka
    Rafał Sroka almost 2 years

    To define a category bit mask enum in Objective-C I used to type:

    typedef NS_OPTIONS(NSUInteger, CollisionCategory)
    {
        CollisionCategoryPlayerSpaceship = 0,
        CollisionCategoryEnemySpaceship = 1 << 0,
        CollisionCategoryChickenSpaceship = 1 << 1,
    };
    

    How can I achieve the same using Swift? I experimented with enums but can't get it working. Here is what I tried so far.

    error screenshot