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