web-dev-qa-db-ja.com

SwiftでSpriteKitのカテゴリビットマスク列挙を定義するにはどうすればよいですか?

Objective-Cでカテゴリビットマスクの列挙型を定義するには、次のように入力しました。

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

Swiftを使用して同じことをするにはどうすればよいですか?列挙型を試してみましたが、機能させることができません。これが私が今までに試したことです。

error screenshot

28
RaffAl

あなたができることはバイナリリテラルを使うことです:0b10b100b100など.

ただし、Swift enumsはビット単位でORできないため、enumsでビットマスクを使用しても意味がありません。NS_OPTIONの代わりに この質問 を確認してください。

19
nschum

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 
19
William T.

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

前述のように、user949350の代わりにリテラル値を使用できます。しかし、彼が指摘するのを忘れていたのは、あなたの生の値は「二乗」でなければならないということです。 Apple=のコードのサンプルがカテゴリを列挙する方法に注意してください。通常の1、2、3、4、5などではなく、1、2、4、8、16です。

したがって、コードでは次のようになります。

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

}

たとえば、プレイヤーノードを敵またはチキンの宇宙船と衝突させたい場合は、次のようにします。

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

ケースをUIntとしてキャストしてみてください。

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

これは私のためにエラーを取り除きます。

1
Connor

Swiftでビットマスクを処理する簡単な方法は、すべての異なる衝突タイプを含むタイプUInt32の列挙を作成することです。つまり、

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

そして、あなたのPlayer Classに物理体を追加し、衝突検出をセットアップします

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

そして、あなたのAttacker Class(または発射体、鳥、流星など)の場合、その物理ボディを次のように設定します。

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

(物理ボディを任意の形状に設定できることに注意してください)

次に、SKPhysicsContactDelegateセットアップがあることを確認し(たとえば、シーンをデリゲートにできる)、optionalプロトコルメソッドを実装します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を追加することで、ゲーム内の衝突をより多く検出できます。

1
Groot

UIntには少しバグがありますが、とにかく32ビットしか使われていないので、これはうまくいきます。また、レーダーを送信することをお勧めします。任意の定数値を使用できるはずです(1 << 2は常に同じです)。

とにかく、UIntのバグを取り除くと、これでうまくいきます

列挙型CollisionCategory:Int {ケースPlayerSpaceship = 0、EnemySpaceShip、PlayerMissile、EnemyMissile

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

私はうまく機能する以下のように使用することを好み、それはあなたの最初の試みに最も近い方法だと思います:

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

PS:これはSwift 4

0
Vetuka

列挙型のある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 
0
wm.p1us