webentwicklung-frage-antwort-db.com.de

Wie definiere ich die Kategorie-Bitmasken-Enumeration für SpriteKit in Swift?

So definieren Sie eine Kategorie-Bitmasken-Enumeration in Objective-C, die zum Schreiben verwendet wurde:

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

Wie kann ich mit Swift dasselbe erreichen? Ich habe mit Aufzählungen experimentiert, kann es aber nicht zum Laufen bringen. Hier ist was ich bisher ausprobiert habe.

error screenshot

28
RaffAl

Sie können die binären Literale verwenden: 0b1, 0b10, 0b100 usw.

In Swift ist es jedoch nicht möglich, bitweise-OR-Enums zu verwenden. Daher hat es wirklich keinen Sinn, Bitmasken in Enums zu verwenden. Check out diese Frage für einen Ersatz für NS_OPTION.

19
nschum

Wenn Sie dieses Swift-Tutorial betrachten, können Sie die gesamte toRaw () - oder rawValue-Konvertierung vermeiden, indem Sie Folgendes verwenden:

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.

Schauen Sie sich das AdvertureBuilding SpriteKit-Spiel an. Sie haben es in Swift neu aufgebaut und Sie können die Quelle auf der iOS8-Dev-Site herunterladen. 

Sie verwenden die folgende Methode zum Erstellen einer Enumeration:

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

Und das Setup ist so

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

Und prüfe wie folgt:

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

Wie von user949350 angemerkt, können Sie stattdessen Literalwerte verwenden. Er hat jedoch vergessen zu erwähnen, dass Ihr Rohwert in "Quadraten" sein sollte. Beachten Sie, wie das Codebeispiel von Apple die Kategorien auflistet. Sie sind 1, 2, 4, 8 und 16 anstelle der üblichen 1, 2, 3, 4, 5 usw.

In Ihrem Code sollte es also so aussehen:

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

}

Und wenn Sie möchten, dass Ihr Spielerknoten beispielsweise mit einem Feind oder einem Hühner-Raumschiff zusammenstößt, können Sie Folgendes tun

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

Versuchen Sie, Ihre Fälle als UInt auszugeben. 

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

Dies beseitigt die Fehler für mich.

1
Connor

Eine einfache Möglichkeit, mit Bitmasken in Swift umzugehen, ist das Erstellen einer Aufzählung vom Typ UInt32, die alle Ihre unterschiedlichen Kollisionstypen enthält. Das ist

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

Fügen Sie dann in Ihrer Player-Klasse einen Physik-Körper hinzu und richten Sie die Kollisionserkennung ein

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

Und für Ihre Attacker-Klasse (oder Projektil, Vogel, Meteor etc.) richten Sie ihren Physikkörper als ein

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

(Beachten Sie, dass Sie den Physik-Körper so einrichten können, dass er die gewünschte Form hat.)

Stellen Sie dann sicher, dass Sie über ein SKPhysicsContactDelegate-Setup verfügen (z. B. können Sie Ihre Szene als Delegat festlegen), und implementieren Sie dann die optional - Protokollmethode 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")
        }

    }

}

Durch das Hinzufügen weiterer ColliderTypes können Sie mehr Kollisionen in Ihrem Spiel erkennen.

1
Groot

Es gibt einen kleinen Fehler mit UInt, aber ich denke, es werden sowieso nur 32 Bits verwendet, was funktionieren würde. Ich würde auch vorschlagen, ein Radar zu senden, Sie sollten einen beliebigen konstanten Wert verwenden können (1 << 2 ist immer gleich).

Wie auch immer, hier ist, sobald sie die Fehler mit UInts beseitigt haben, würde dies funktionieren

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()
0
rougeExciter

Ich ziehe es vor, wie unten zu verwenden, was gut funktioniert und ich denke, es ist der beste Weg zu Ihrem ursprünglichen Versuch:

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

P.S .: Dies ist Swift 4

0
sc13

Swift 3 mit Aufzählung:

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