如何在Swift中为SpriteKit定义类别位掩码枚举?

时间:2014-06-05 20:30:28

标签: ios objective-c swift sprite-kit bit-masks

在Objective-C中定义类别位掩码枚举我曾经输入:

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

如何使用Swift实现相同目标?我尝试了枚举,但无法使其正常工作。这是我到目前为止所尝试的内容。

error screenshot

9 个答案:

答案 0 :(得分:19)

你可以做的是使用二进制文字:0b10b100b100等。

但是,在Swift中你不能按位OR枚举,所以在枚举中使用位掩码确实没有意义。查看this question以获取NS_OPTION的替换。

答案 1 :(得分:19)

如果查看this swift tutorial,可以使用以下命令来避免整个toRaw()或rawValue转换:

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 

答案 2 :(得分:9)

看看AdvertureBuilding SpriteKit游戏。他们在Swift中重建了它,您可以在iOS8开发站点上下载源代码。

他们使用以下创建枚举的方法:

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

设置就像这样

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

并按照以下方式检查:

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
    }
}

答案 3 :(得分:4)

如上所述,user949350可以改为使用文字值。但他忘了指出的是,你的原始价值应该是&#34; square&#34;。请注意Apple的代码示例如何枚举类别。它们分别为1,2,4,8和16,而不是通常的1,2,3,4,5等。

所以在你的代码中它应该是这样的:

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

}

例如,如果您希望玩家节点与敌人或鸡太空船发生碰撞,您可以执行以下操作:

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

答案 4 :(得分:1)

尝试将您的案例转换为UInt。

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

这为我摆脱了错误。

答案 5 :(得分:1)

在swift中处理位掩码的一种简单方法是创建一个包含所有不同碰撞类型的UInt32类型的枚举。那是

enum ColliderType: UInt32 {
    case Player = 1
    case Attacker = 2
}

然后在播放器类中添加物理主体并设置碰撞检测

physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(size.width, size.height))
physicsBody.categoryBitMask = ColliderType.Player.toRaw()
physicsBody.contactTestBitMask = ColliderType.Attacker.toRaw()
physicsBody.collisionBitMask = ColliderType.Attacker.toRaw()

对于攻击者类(或射弹,鸟类,流星等)设置其物理机构

physicsBody = SKPhysicsBody(circleOfRadius: size.width / 2)
physicsBody.categoryBitMask = ColliderType.Attacker.toRaw()
physicsBody.contactTestBitMask = ColliderType.Player.toRaw()
physicsBody.collisionBitMask = ColliderType.Player.toRaw()

(请注意,您可以将物理主体设置为您想要的任何形状)

然后确保您有SKPhysicsContactDelegate设置(例如,您可以让您的场景成为委托),然后实施可选协议方法didBeginContact

class GameScene: SKScene, SKPhysicsContactDelegate {

    override func didMoveToView(view: SKView) {

        physicsWorld.contactDelegate = self
        // Additional setup...

    }

    func didBeginContact(contact: SKPhysicsContact!) {

        println("A collision was detected!")

        if (contact.bodyA.categoryBitMask == ColliderType.Player.toRaw() &&
            contact.bodyB.categoryBitMask == ColliderType.Attacker.toRaw()) {

            println("The collision was between the Player and the Attacker")
        }

    }

}

通过添加更多ColliderTypes,您可以在游戏中检测到更多碰撞。

答案 6 :(得分:0)

UInt存在一些错误,但考虑到我认为只使用了32位,这将起作用。我还建议提交一个雷达,你应该可以使用任何常数值(1 <&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;

无论如何,一旦他们摆脱了UI的错误,这将有效

枚举CollisionCategory:Int {     case PlayerSpaceship = 0,EnemySpaceShip,PlayerMissile,EnemyMissile

func collisionMask()->Int{
    switch self{
    case .PlayerSpaceship:
        return 0;
    default:
        return 1 << (self.toRaw()-1)
    }
}
}
CollisionCategory.PlayerMissle.collisionMask()

答案 7 :(得分:0)

Swift 3 with enum:

enum PhysicsCategory: UInt32 {
  case none = 1
  case monster = 2
  case projectile = 4
  case wall = 8
}

monster.physicsBody?.categoryBitMask = PhysicsCategory.monster.rawValue 
monster.physicsBody?.contactTestBitMask = PhysicsCategory.projectile.rawValue
monster.physicsBody?.collisionBitMask = PhysicsCategory.none.rawValue 

答案 8 :(得分:0)

我更喜欢使用如下所示的方法,该方法效果很好,我认为这是最接近您原始尝试的方法:

Post

P.S .:这是Swift 4