ios - Cómo detectar colisiones en Swift, Sprite kit
sprite-kit skphysicsbody (1)
Estaba programando este sencillo juego espacial en Swift hasta que encontré el problema de detectar colisiones. Después de buscar en foros, tutoriales, etc., intenté implementar colisiones declarando las máscaras de bits así:
objeto 1
enemy?.physicsBody = SKPhysicsBody(circleOfRadius: ((enemy?.size.width)!/2))
enemy?.physicsBody?.categoryBitMask = enemyBitMask
enemy?.physicsBody?.contactTestBitMask = bulletBitMask
enemy?.physicsBody?.collisionBitMask = 0
objeto 2
bullet?.physicsBody? = SKPhysicsBody(rectangleOf: (bullet?.size)!)
bullet?.physicsBody?.categoryBitMask = bulletBitMask
bullet?.physicsBody?.contactTestBitMask = enemyBitMask
bullet?.physicsBody?.collisionBitMask = 0
bullet?.physicsBody?.usesPreciseCollisionDetection = true
También puse una declaración impresa en el
func didBegin(_ contact: SKPhysicsContact) { print("Hello") }
Así es como configuro mis sprites:
func CreateNewEnemy() {
var enemy : SKSpriteNode?
let moveEnemyDown = SKAction.repeatForever(SKAction.moveBy(x: 0, y: -1, duration: 0.01))
let rotateEnemy = SKAction.repeatForever(SKAction.rotate(byAngle: 25, duration: 5))
let enemyXpos = randomNum(high: self.frame.size.width/2, low: -1 * self.frame.size.width/2)
let enemyYpos = randomNum(high: 2.5*self.frame.size.height, low: self.frame.size.height/2)
let enemyOrigin : CGPoint = CGPoint(x: enemyXpos, y: enemyYpos)
enemy = SKSpriteNode(imageNamed: possibleEnemyImage[Int(arc4random_uniform(4))])
print(enemy?.size.height)
enemy?.scale(to: CGSize(width: player.size.height, height: player.size.height))
print(enemy?.size.height)
enemy?.position = enemyOrigin
enemy?.run(moveEnemyDown)
enemy?.run(rotateEnemy)
let enemyRadius : CGFloat = (enemy?.size.width)!/2
print(enemyRadius)
enemy?.physicsBody? = SKPhysicsBody(circleOfRadius: enemyRadius)
enemy?.physicsBody?.categoryBitMask = enemyCategory
enemy?.physicsBody?.contactTestBitMask = bulletCategory
enemy?.physicsBody?.collisionBitMask = 0
enemy?.zPosition = 1
enemiesArray.append(enemy!)
self.addChild(enemy!)
}
para crear enemigo (Llamado en mover para ver la función)
func CreateAllEnemies(amountOfEnemies : UInt8) {
for _ in 0...amountOfEnemies {
CreateNewEnemy()
}
}
y el otro sprite
func CreateNewBullet() {
let bulletOrigin : CGPoint = CGPoint(x: player.position.x, y: player.position.y+player.size.height/2)
let moveBulletUp = SKAction.repeatForever(SKAction.moveBy(x: 0, y: 3, duration: 0.01))
var bullet : SKSpriteNode?
bullet = SKSpriteNode(imageNamed: "bulletImage")
bullet?.position = bulletOrigin
bullet?.run(moveBulletUp)
bullet?.physicsBody? = SKPhysicsBody(rectangleOf: (bullet?.size)!)
bullet?.physicsBody?.categoryBitMask = bulletCategory
bullet?.physicsBody?.contactTestBitMask = enemyCategory
bullet?.physicsBody?.collisionBitMask = 0
bullet?.physicsBody?.isDynamic = true
bullet?.physicsBody?.usesPreciseCollisionDetection = true
bullet?.zPosition = 1
bulletsArray.append(bullet!)
self.addChild(bullet!)
}
este se crea con un temporizador
bulletTimer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(CreateNewBullet) , userInfo: nil, repeats: true)
Desafortunadamente, no imprime nada en la consola después de ver los dos objetos en contacto.
-
Defina categorías únicas, asegúrese de que su clase sea un
SKPhysicsContactDelegate
ySKPhysicsContactDelegate
el delegado de contacto de física:
//Physics categories
let enemyCategory: UInt32 = 1 << 1
let bulletCategory: UInt32 = 1 << 2
class GameScene: SKScene, SKPhysicsContactDelegate {
physicsWorld.contactDelegate = self
-
Asigna las categorías (generalmente en
didMove(to view:)
:enemy.physicsBody.catgeoryBitMask = enemyCategory bullet.physicsBody.catgeoryBitMask = bulletCategory
(Asegúrate de haber creado cuerpos físicos para cada nodo)
- Configurar colisiones:
enemy.physicsBody?.collisionBitMask = 0 // enemy collides with nothing
bullet.physicsBody?.collisionBitMask = 0 // bullet collides with nothing
o incluso:
for node in [enemy, bullet] {
node.physicsBody?.collisionBitMask = 0 // collides with nothing
}
-
Configurar contactos
bullet.physicsBody?.collisionBitMask = enemyCategory // bullet contacts enemy
Asegúrese de que al menos uno de los objetos involucrados en cada contacto potencial tenga la propiedad
isDynamic
en su cuerpo de física establecido en
true
, o no se generará ningún contacto.
No es necesario que ambos objetos sean dinámicos.
Ahora deberías hacer que te
didBegin
llamar cuando la bala y el enemigo entren en contacto.
Podrías codificar
didBegin
esta manera:
func didBegin(_ contact: SKPhysicsContact) {
print("didBeginContact entered for /(String(describing: contact.bodyA.node!.name)) and /(String(describing: contact.bodyB.node!.name))")
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case bulletCategory | enemyCategory:
print("bullet and enemy have contacted.")
let bulletNode = contact.bodyA.categoryBitMask == bulletCategory ? contact.bodyA.node : contact.bodyB.node
enemyHealth -= 10
bulletNode.removeFromParent
default:
print("Some other contact occurred")
}
}