tutorial spritekit ios objective-c swift sprite-kit bit-masks

ios - tutorial - ¿Cómo definir la enumeración de máscara de bits de categoría para SpriteKit en Swift?



spritekit swift 4 (8)

Como lo señaló, user949350 puede usar valores literales en su lugar. Pero lo que olvidó señalar es que su valor bruto debe estar en "cuadrados". Observe cómo la muestra de código de Apple enumera las categorías. Son 1, 2, 4, 8 y 16, en lugar de los habituales 1, 2, 3, 4, 5, etc.

Entonces en tu código debería ser algo como esto:

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

}

Y si quieres que tu nodo de jugador colisione con una nave espacial enemiga o de pollo, por ejemplo, puedes hacer algo como esto:

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

Para definir una categoría de máscara de bits enumeración en Objective-C solía escribir:

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

¿Cómo puedo lograr lo mismo usando Swift ? Experimenté con enumeraciones pero no puedo hacer que funcione. Aquí es lo que he intentado hasta ahora.


Echa un vistazo al juego AdvertureBuilding SpriteKit. Lo reconstruyeron en Swift y puedes descargar la fuente en el sitio de desarrollo de iOS8.

Están utilizando el siguiente método para crear una enumeración:

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

Y la configuración es así.

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

Y compruebe así:

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


Hay un pequeño error con UInt, pero dado que creo que solo se usan 32 bits de todas formas, esto funcionaría. También sugeriría enviar un radar, debería poder usar cualquier valor constante (1 << 2 siempre será el mismo)

De todos modos, aquí hay una vez que se han deshecho de los errores con UInts, esto funcionaría

enumeración 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()


Intenta lanzar tus casos como UInt.

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

Esto elimina los errores para mí.


Lo que podrías hacer es usar los literales binarios: 0b1 , 0b10 , 0b100 , etc.

Sin embargo, en Swift no puedes enumerar en modo bit-OR, por lo que realmente no tiene sentido usar máscaras de bits en enumeraciones. Echa un vistazo a esta pregunta para un reemplazo para NS_OPTION.


Si observa este tutorial rápido , puede evitar la conversión completa de toRaw () o rawValue usando:

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


Una forma fácil de manejar las máscaras de bits en swift es crear una enumeración de tipo UInt32 que contenga todos sus diferentes tipos de colisión. Es decir

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

Y luego, en tu clase de jugador, agrega un cuerpo de física y configura la detección de colisión

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

Y para su Clase de atacante (o proyectil, ave, meteoro, etc.) configure su cuerpo físico como

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

(Tenga en cuenta que puede configurar el cuerpo de física para que tenga la forma que desee)

Luego, asegúrese de tener una configuración de SKPhysicsContactDelegate (por ejemplo, puede dejar que su escena sea el delegado) y luego implemente el método de protocolo opcional 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") } } }

Al agregar más ColliderTypes puedes detectar más colisiones en tu juego.


Swift 3 con enumeración:

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