web-dev-qa-db-fra.com

Comment définir l'énumération du masque de bits de catégorie pour SpriteKit dans Swift?

Pour définir une énumération de masque de bits de catégorie dans Objective-C, je tapais:

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

Comment puis-je obtenir le même résultat avec Swift? J'ai expérimenté des énumérations mais je ne peux pas le faire fonctionner. Voici ce que j'ai essayé jusqu'à présent.

error screenshot

28
RaffAl

Ce que vous pouvez faire, c'est utiliser les littéraux binaires: 0b1, 0b10, 0b100, etc.

Cependant, dans Swift, vous ne pouvez pas utiliser d'énums bitwise-OR, il est donc inutile d'utiliser des masques de bits dans les énumérations. Découvrez cette question pour un remplacement de NS_OPTION.

19
nschum

Si vous regardez ce didacticiel Swift , vous pouvez éviter la conversion totale de toRaw () ou de rawValue en utilisant:

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.

Jetez un coup d'œil au jeu AdvertureBuilding SpriteKit. Ils l'ont reconstruit dans Swift et vous pouvez télécharger le code source sur le site de développement iOS8. 

Ils utilisent la méthode suivante pour créer une énumération:

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

Et la configuration est comme ça

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

Et vérifiez comme ceci:

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

Comme indiqué par user949350, vous pouvez utiliser des valeurs littérales à la place. Mais ce qu'il a oublié de souligner, c'est que votre valeur brute devrait être en "carrés". Remarquez comment l'échantillon de code d'Apple énumère les catégories. Ils sont 1, 2, 4, 8 et 16, au lieu de 1, 2, 3, 4, 5 etc.

Donc, dans votre code, cela devrait ressembler à ceci:

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

}

Et si vous voulez que votre nœud de joueur entre en collision avec un vaisseau spatial ennemi ou de poulet, par exemple, vous pouvez faire quelque chose comme ceci:

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

Essayez de lancer vos cas comme UInt. 

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

Cela supprime les erreurs pour moi.

1
Connor

Un moyen facile de gérer les masques de bits dans Swift consiste à créer une énumération de type UInt32 contenant tous vos différents types de collision. C'est

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

Et ensuite dans votre Player Class ajoutez un corps physique et configurez la détection de collision

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

Et pour votre Classe d'attaquant (ou projectile, oiseau, météore, etc.), configurez son corps physique comme suit:

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

(Notez que vous pouvez configurer le corps physique de manière à ce qu'il soit sous la forme de votre choix)

Assurez-vous ensuite que vous avez une configuration SKPhysicsContactDelegate (vous pouvez par exemple laisser votre scène être le délégué), puis implémentez la méthode de protocole 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")
        }

    }

}

En ajoutant plus de ColliderTypes, vous pouvez détecter plus de collisions dans votre jeu.

1
Groot

Il y a un petit bug avec UInt, mais étant donné que je pense que seulement 32 bits sont utilisés de toute façon, cela fonctionnerait. Je suggérerais également de soumettre un radar, vous devriez pouvoir utiliser n'importe quelle valeur constante (1 << 2 seront toujours les mêmes)

Quoi qu'il en soit, voici une fois qu'ils se sont débarrassés des bugs avec UInts, cela fonctionnerait

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

Je préfère utiliser comme ci-dessous ce qui fonctionne très bien et je pense que c'est le moyen le plus proche de votre tentative initiale:

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

P.S .: C'est Swift 4

0
sc13

Swift 3 avec 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 
0
wm.p1us