iosswiftsprite-kitskemitternode

Do I have to manually remove emitter node from parent after it's done playing?


I currently display particle effects once my sprite collides with another sprite in-game.

I have this snippet of code:

let sparkParticle = SKEmitterNode(fileNamed: "SparkParticle.sks")
if sparkParticle.parent == nil
{
    sparkParticle.position = mySprite.position
    self._particleLayer.addChild(sparkParticle)
}
sparkParticle.resetSimulation()

The particle I created has a birthrate of 1000 particles with a maximum of 100. I set the position of the particle emitter node to where my sprite is currently on screen. Then, I add it as a child of the particle layer node.

My question is, do I have to manually remove the particle emitter node from its parent after it's finished? Or does Sprite Kit automatically remove it after it has finished playing?

Since my project is designed to have the sprites collide with each other a lot, I want to make sure if I still need to handle this manually to prevent memory leaks (the particle layer having a lot of child emitter nodes that are finished playing already)


Solution

  • The short answer is no you don't need to worry about it in your case. But if the particle emitter is off the screen or running permanently it becomes more of an issue. When the scene is deallocated the SKEmitterNode will be removed automatically. Because an SKEMitterNode is an SKNode that is inserted into the node tree.

    However, If you want to be extra careful, you can manually and recursively stop all actions and emitters before the scene deallocates with the following method. I was having problems with delayed SKActions firing after the scene was deallocated and crashing my app, so I manually stop them all before the scene is deallocated.

    Keep a reference to the old scene and call this on the scene:

    +(void)recursivelyStopAndRemoveNode:(SKNode*)node {
    
        // recursively call all children
        for (SKNode *childNode in [node children]) {
            [PCUtils recursivelyStopAndRemoveNode:childNode];
        }
    
        // stop emitters
        if ( [node isKindOfClass:[SKEmitterNode class]]) {
            SKEmitterNode* sken = (SKEmitterNode*)node;
            sken.targetNode = nil;
            sken.particleBirthRate = 0;
            NSLog(@"stopping emitter %@", node.name);
        }
    
        // stop any running actions
        [node removeAllActions];
    
        // remove me from my parent.
        [node removeFromParent];
    
    }
    

    Then, use it in your GameViewController or wherever you are changing scenes:

    SKScene *oldScene = skView.scene;
    [skView presentScene:newScene transition:nil];
    if (oldScene) 
       [PCUtils recursivelyStopAndRemoveNode:oldScene];