簡體   English   中英

如何在 Swift 中為 SpriteKit 定義類別位掩碼枚舉?

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

要在 Objective-C 中定義類別位掩碼枚舉,我曾經鍵入:

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

如何使用Swift實現相同的目標? 我嘗試了枚舉,但無法使其正常工作。 這是我到目前為止所嘗試的。

錯誤截圖

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

然而,在 Swift 中你不能按位或枚舉,所以在枚舉中使用位掩碼真的沒有意義。 查看此問題以替代 NS_OPTION。

如果您查看此 swift 教程,您可以使用以下方法避免整個 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 

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

正如 user949350 所指出的,您可以改用文字值。 但是他忘記指出的是,您的原始值應該是“平方”。 請注意 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()

嘗試將您的案例轉換為 UInt。

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

這為我消除了錯誤。

在 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 )然后實現可選的協議方法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,您可以檢測游戲中的更多碰撞。

UInt 有一些錯誤,但鑒於我認為無論如何都只使用了 32 位,這會起作用。 我還建議提交雷達,您應該可以使用任何常量值(1 << 2 將始終相同)

無論如何,一旦他們擺脫了 UInts 的錯誤,這將起作用

enum 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()

帶有枚舉的 Swift 3:

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 

我更喜歡使用下面這樣的方法,它工作得很好,我認為這是最接近您最初嘗試的方法:

// MARK: Categories - UInt32
let playerCategory:UInt32 = 0x1 << 0
let obstacleCategory:UInt32 = 0x1 << 1
let powerUpCategory:UInt32 = 0x1 << 2

PS:這是 Swift 4

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM