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.
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.
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
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
}
}
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()
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.
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.
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()
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
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