user594883 user594883 - 7 months ago 9
Swift Question

Spritekit game crashes (because of SKLightNode threading issue?)

I'm trying to create a simple game for my Kids. I'm trying to implement light and emitter nodes. However the game crashes on collision which should result to gameOverScene. The strange thing is that the code completes ok if I add a brakepoint. Here's the code:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
touch = touches.first!
turnOnLightNode(touch.locationInNode(self))
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
touch = touches.first!
turnOnLightNode(touch.locationInNode(self))
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
removeLightNode()
}
func removeLightNode(){
var nodeToRemove = self.childNodeWithName("light")
while(nodeToRemove != nil && endOfSceneCollision == false) {
nodeToRemove?.removeFromParent()
nodeToRemove = self.childNodeWithName("light")
}
nodeToRemove = self.childNodeWithName("touchEmitterNode")
while(nodeToRemove != nil && endOfSceneCollision == false) {
nodeToRemove?.removeFromParent()
nodeToRemove = self.childNodeWithName("touchEmitterNode")
}
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
removeLightNode()
}
func turnOnLightNode(point: CGPoint){

removeLightNode()

light.name = "light"
light.categoryBitMask = 3
light.position = point
light.zPosition = 19.0
light.falloff = 0.5
light.enabled = true
light.lightColor = UIColor(red: 161/255, green: 218/255, blue: 237/255, alpha: 0.5)
light.shadowColor = UIColor(red: 161/255, green: 218/255, blue: 237/255, alpha: 0.5)
light.ambientColor = UIColor(red: 220/255, green: 220/255, blue: 220/255, alpha: 0.3)

addChild(light)

touchEmitter!.name = "touchEmitterNode"
touchEmitter!.position = point
touchEmitter!.zPosition = 100//gameFieldParticlesZPosition
addChild(touchEmitter!)
}

func didBeginContact(contact: SKPhysicsContact) {
var ballBody: SKPhysicsBody?
var lineBody: SKPhysicsBody?
var collidedBallNode: SKSpriteNode?

if contact.bodyA.categoryBitMask == 2 && contact.bodyB.categoryBitMask == 1 {
print("didBeginContactAB")

lineBody = contact.bodyA
ballBody = contact.bodyB
collidedBallNode = contact.bodyB.node as? SKSpriteNode
}
if contact.bodyA.categoryBitMask == 1 && contact.bodyB.categoryBitMask == 2 {
print("didBeginContactBA")

lineBody = contact.bodyB
ballBody = contact.bodyA
collidedBallNode = contact.bodyA.node as? SKSpriteNode
}
if contact.bodyA.categoryBitMask == 1 && contact.bodyB.categoryBitMask == 4 {
//audioController.playSound(electricBounceSound, volume: 1.0)
}
if contact.bodyA.categoryBitMask == 4 && contact.bodyB.categoryBitMask == 1 {
//audioController.playSound(electricBounceSound, volume: 1.0)
}
if contact.bodyA.categoryBitMask == 1 && contact.bodyB.categoryBitMask == 1 {
//audioController.playSound(electricNoiseSound, volume: 1.0)
}

if(collidedBallNode != nil){
gotoGameOverScene(collidedBallNode!)

}
}
func gotoGameOverScene(explodingBallNode: SKSpriteNode){
print("step 1") //IF BREAKPOINT HERE, ALL EXECUTES OK
self.runAction(SKAction.waitForDuration(2.5), completion: {
print("step 2")
let gameOverScene = GameOverScene(size: self.size)
print("step 3")
self.view?.presentScene(gameOverScene, transition: reveal)
print("step 4")
})
}


And it results to this:

didBeginContactAB
step 1
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attemped to add a SKNode which already has a parent: <SKLightNode> name:'light' position:{296.99994, 191.49995} scale:{1.00, 1.00} accumulatedFrame:{{297, 191.5}, {0, 0}}'
*** First throw call stack:
(
0 CoreFoundation 0x01384a14 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00b5de02 objc_exception_throw + 50
2 CoreFoundation 0x0138493d +[NSException raise:format:] + 141


BUT if I put debugger breakpoint before the following line:

print("step 1")


Code executes succesfully. Must be a thread / synchronization issue but this beats my knowhow over Spritekit / Swift. Could someone help me with fixing this?

Answer

Ahhh...I got it. Stupid piece of code at removeLightNode function. This caused remove not to work after collision: while(nodeToRemove != nil && endOfSceneCollision == false)