播放完毕后,我是否必须从父级手动移除发射器节点?

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

我目前在我的 sprite 与游戏中的另一个 sprite 碰撞时显示粒子效果。

我有这段代码:

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

我创建的粒子有 1000 个粒子的出生率,最大值为 100。我将粒子发射器节点的位置设置为我的精灵当前在屏幕上的位置。然后,我将它添加为粒子层节点的子节点。

我的问题是,粒子发射器节点完成后是否必须手动从其父节点移除?还是Sprite Kit播放完后会自动移除?

由于我的项目旨在让精灵相互碰撞很多,我想确定我是否仍然需要手动处理这个以防止内存泄漏(粒子层有很多子发射器节点已经玩完了)

简短的回答是不,你不需要担心你的情况。但是,如果粒子发射器不在屏幕上或 运行 永久存在,它就会成为一个更大的问题。当场景被释放时,SKEmitterNode 将被自动移除。因为一个SKEMitterNode就是插入到节点树中的SKNode。

但是,如果你想格外小心,你可以手动递归地停止场景释放之前的所有动作和发射器,方法如下。在场景被解除分配并导致我的应用程序崩溃后,我遇到了延迟 SKActions 触发的问题,因此我在场景被解除分配之前手动将它们全部停止。

保留对旧场景的引用,并在场景中调用:

+(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];

}

然后,在您的 GameViewController 或您要更改场景的任何地方使用它:

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

我实际上建议您移除发射器。我最近在我的游戏中遇到一个问题,因为我没有移除发射器,它会开始非常严重地滞后。这是一个问题,当添加发射器时我能够 100% 重现,所以我知道它们是帧速率下降的唯一原因。在我开始看到延迟之前,大约需要 20 个未移除的发射器。

其实很简单。您可以创建一个 SKAction 序列,其中包含一个等待动作(1 秒或稍微超过您的效果长度)和一个 removeFromParent 动作。

这将在它完成后立即摆脱它,并确保您的帧率不会下降。