Search code examples
swiftcrashsprite-kitrestartskemitternode

SKEmitterNode Causing Crash on Scene Restart


I created an SKEmitterNode to attach to my player after he dies. It's a very simple smoke one. The problem is, it is crashing the game when I either:

1) Hit the retry button and transition to the same scene, it will, at a random time, crash the game with an EXC_BAD_ACCESS error.

2) Return to the home screen and hit play and transition to that game scene after dying at least once and creating the emitter node.

Currently the SKEmitterNode is a class variable optional. When the player dies, they set up the SKEmitterNode and attaches it to the scene.

    // Add death smoke
    let smokePath: String = NSBundle.mainBundle().pathForResource("playerDeathSmoke", ofType: "sks")!
    self.deathSmokeEmitter = NSKeyedUnarchiver.unarchiveObjectWithFile(smokePath) as? SKEmitterNode
    self.deathSmokeEmitter?.name = "deathSmokeEmitter"
    if let deathEmitter = self.deathSmokeEmitter {
        deathEmitter.targetNode = self.scene
        self.addChild(deathEmitter)
    }

"self.addChild(deathEmitter)" will cause the crash AFTER you reload the scene (the smoke DOES appear). This is the SAME way the example code in the SKEmitterNode documentation adds the emitter node.

I also tried various things to fix it already like overriding the removeFromParent method on the Player sprite and running "removeFromParent" on it myself before transitioning scenes.

    override func removeFromParent() {
         self.deathSmokeEmitter?.removeFromParent()
         //self.deathSmokeEmitter?.targetNode = nil

         super.removeFromParent()
     }

After doing this the crash will only occur when RETURNING to the home screen first and then transitioning back to the game scene. That means I can do quick retries over and over again as many times as I want if that is commented out, but it still crashes if I go back to the home scene and return to the game scene. Also, when it crashes this way, the stack trace shows this last method before crashing:

 [SKEffectNode dealloc]

Please let me know if you have any ideas and thanks!

PS: I do nothing strange during my transitions. I simply instantiate a transition and push the next scene. I was relying on SpriteKit to take care of all the cleaning for me.


Solution

  • So I found out how to fix this (I pretty much had it figured out when I asked the question) but for clarification Ill type it out.

    For some reason, SpriteKit in iOS 8 does not remove the smoke emitter from the Player sprite when switching scenes. This somehow causes a crash as it tries to do some logic on it in the next scene for some reason.

    What I had above was almost correct. First override the sprite with the particle emitter child's removeFromParent() method like this

    // Sprite with ParticleEmitterNode child attached to it's method
    override func removeFromParent() {
         self.deathSmokeEmitter?.removeFromParent()
    
         super.removeFromParent()
     }
    

    Before switching scenes, just do a spriteWithEmitterChild.removeFromParent() to remove the sprite (with the emitter as a child) from the scene, which will call the overridden method and remove the smoke emitter from the sprite BEFORE removing the sprite from the scene.