I am trying to learn SpriteKit, following this tutorial
Everything was working fine until I wanted to add another collision between two different objects. I have Enemy nodes, Player(spaceship), Projectiles and Meteors, the Enemies come down and you shoot them from the ship with projectiles and avoid the meteors. I have tried setting up the physics category struct, setting correct physics categories for each node and creating the collision functions.
Problem is, The meteors are triggering the function that is supposed to happen when the meteors hit the spaceship character when they hit the enemies also, I tried changing things and the collisions just mix up but I can never quite get it right. I just want the projectiles to hit the enemy ships, and the meteors to damage the players ship.
Here is what I have done:
struct PhysicsCategory {
static let none : UInt32 = 0
static let all : UInt32 = UInt32.max
static let monster : UInt32 = 0x2 // 1
static let projectile: UInt32 = 0x3 // 2
static let spaceship : UInt32 = 0x4
static let meteor : UInt32 = 0x5
static let edge : UInt32 = 0x6
}
Spaceship:
spaceship.physicsBody = SKPhysicsBody(rectangleOf: spaceship.size) // 1
spaceship.physicsBody?.isDynamic = true // 2
spaceship.physicsBody?.categoryBitMask = PhysicsCategory.spaceship // 3
spaceship.physicsBody?.contactTestBitMask = PhysicsCategory.meteor// 4
spaceship.physicsBody?.collisionBitMask = PhysicsCategory.none // 5
Enemy:
monster.physicsBody = SKPhysicsBody(rectangleOf: monster.size) // 1
monster.physicsBody?.isDynamic = true // 2
monster.physicsBody?.categoryBitMask = PhysicsCategory.monster // 3
monster.physicsBody?.contactTestBitMask = PhysicsCategory.projectile // 4
monster.physicsBody?.collisionBitMask = PhysicsCategory.none // 5
Projectile:
projectile.physicsBody = SKPhysicsBody(rectangleOf: projectile.size)
projectile.physicsBody?.isDynamic = true
projectile.physicsBody?.categoryBitMask = PhysicsCategory.projectile
projectile.physicsBody?.contactTestBitMask = PhysicsCategory.monster
projectile.physicsBody?.collisionBitMask = PhysicsCategory.none
projectile.physicsBody?.usesPreciseCollisionDetection = true
Meteor:
monster.physicsBody = SKPhysicsBody(rectangleOf: monster.size) // 1
monster.physicsBody?.isDynamic = true // 2
monster.physicsBody?.categoryBitMask = PhysicsCategory.meteor // 3
monster.physicsBody?.contactTestBitMask = PhysicsCategory.none // 4
monster.physicsBody?.collisionBitMask = PhysicsCategory.none// 5
Finally, the physics functions:
func projectileDidCollideWithMonster(projectile: SKSpriteNode, monster: SKSpriteNode) {
print("Hit")
run(SKAction.playSoundFileNamed("Dull-Impact-Hit.wav", waitForCompletion: false))
hits += 1
scoreLabel.text = "Score: \(hits)/25"
if hits == 25 {
self.removeAction(forKey: "addMonster")
self.scoreLabel.text = "Victory!"
}
monster.removeAction(forKey: "spaceshipMoving")
monster.run(SKAction.animate(with: explosionAnimation,
timePerFrame: 0.1,
resize: false,
restore: true))
monster.run(SKAction.animate(with: explosionAnimation,
timePerFrame: 0.1,
resize: false,
restore: true)) {
monster.removeFromParent()
}
projectile.removeFromParent()
}
func meteorDidCollideWithSpaceship(meteor: SKSpriteNode, spaceship: SKSpriteNode) {
print("Ouch")
run(SKAction.playSoundFileNamed("Dull-Impact-Hit.wav", waitForCompletion: false))
health -= 1
healthLabel.text = String(health)
print("health" + String(health))
if health == 0 {
scoreLabel.text = "You died!"
healthLabel.text = "☠"
self.view?.isUserInteractionEnabled = false
self.spaceship.removeFromParent()
}
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
// 1
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
// 2
if ((firstBody.categoryBitMask & PhysicsCategory.monster != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.projectile != 0)) {
if let monster = firstBody.node as? SKSpriteNode,
let projectile = secondBody.node as? SKSpriteNode {
projectileDidCollideWithMonster(projectile: projectile, monster: monster)
}
}
if ((firstBody.categoryBitMask & PhysicsCategory.spaceship != 0 ) &&
(secondBody.categoryBitMask & PhysicsCategory.meteor != 0 )) {
if let meteor = firstBody.node as? SKSpriteNode,
let spaceship = secondBody.node as? SKSpriteNode {
meteorDidCollideWithSpaceship(meteor: meteor, spaceship: spaceship)
}
}
}
}
How can I get my intended behaviors? Thank you.