SKEmitterNode 在场景重启时导致崩溃
SKEmitterNode Causing Crash on Scene Restart
我创建了一个 SKEmitterNode 在我的玩家死后附加到他身上。这是一款非常简单的烟具。问题是,当我执行以下任一操作时游戏会崩溃:
1) 点击重试按钮并转换到同一场景,它会在随机时间使游戏崩溃并出现 EXC_BAD_ACCESS 错误。
2) Return 到主屏幕并点击播放并在至少死亡一次并创建发射器节点后转换到该游戏场景。
目前 SKEmitterNode 是一个 class 变量可选。当玩家死亡时,他们设置 SKEmitterNode 并将其附加到场景。
// 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)" 将在您重新加载场景后导致崩溃(烟雾确实出现)。这与 SKEmitterNode 文档中的示例代码添加发射器节点的方式相同。
我也尝试了各种方法来修复它,比如在转换场景之前重写 Player 精灵上的 removeFromParent 方法和 运行 "removeFromParent" 自己。
override func removeFromParent() {
self.deathSmokeEmitter?.removeFromParent()
//self.deathSmokeEmitter?.targetNode = nil
super.removeFromParent()
}
执行此操作后,只有在先返回主屏幕然后再转换回游戏场景时才会发生崩溃。这意味着如果注释掉了,我可以一遍又一遍地快速重试,但如果我回到主场景并 return 回到游戏场景,它仍然会崩溃。此外,当它以这种方式崩溃时,堆栈跟踪显示崩溃前的最后一个方法:
[SKEffectNode dealloc]
如果您有任何想法,请告诉我,谢谢!
PS:我在过渡期间没有做任何奇怪的事情。我只是简单地实例化一个转换并推送下一个场景。我依靠 SpriteKit 为我处理所有清洁工作。
所以我找到了解决这个问题的方法(当我问这个问题时我几乎已经弄清楚了)但是为了澄清我会把它打出来。
由于某些原因,iOS8 中的 SpriteKit 在切换场景时不会从 Player 精灵中移除烟雾发射器。这不知何故导致崩溃,因为它出于某种原因试图在下一个场景中对其执行一些逻辑。
我上面的几乎是正确的。首先使用粒子发射器子项的 removeFromParent() 方法覆盖精灵
// Sprite with ParticleEmitterNode child attached to it's method
override func removeFromParent() {
self.deathSmokeEmitter?.removeFromParent()
super.removeFromParent()
}
在切换场景之前,只需执行 spriteWithEmitterChild.removeFromParent() 从场景中移除精灵(将发射器作为子画面),这将调用覆盖的方法并从精灵中移除烟雾发射器 BEFORE从场景中移除精灵。
我创建了一个 SKEmitterNode 在我的玩家死后附加到他身上。这是一款非常简单的烟具。问题是,当我执行以下任一操作时游戏会崩溃:
1) 点击重试按钮并转换到同一场景,它会在随机时间使游戏崩溃并出现 EXC_BAD_ACCESS 错误。
2) Return 到主屏幕并点击播放并在至少死亡一次并创建发射器节点后转换到该游戏场景。
目前 SKEmitterNode 是一个 class 变量可选。当玩家死亡时,他们设置 SKEmitterNode 并将其附加到场景。
// 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)" 将在您重新加载场景后导致崩溃(烟雾确实出现)。这与 SKEmitterNode 文档中的示例代码添加发射器节点的方式相同。
我也尝试了各种方法来修复它,比如在转换场景之前重写 Player 精灵上的 removeFromParent 方法和 运行 "removeFromParent" 自己。
override func removeFromParent() {
self.deathSmokeEmitter?.removeFromParent()
//self.deathSmokeEmitter?.targetNode = nil
super.removeFromParent()
}
执行此操作后,只有在先返回主屏幕然后再转换回游戏场景时才会发生崩溃。这意味着如果注释掉了,我可以一遍又一遍地快速重试,但如果我回到主场景并 return 回到游戏场景,它仍然会崩溃。此外,当它以这种方式崩溃时,堆栈跟踪显示崩溃前的最后一个方法:
[SKEffectNode dealloc]
如果您有任何想法,请告诉我,谢谢!
PS:我在过渡期间没有做任何奇怪的事情。我只是简单地实例化一个转换并推送下一个场景。我依靠 SpriteKit 为我处理所有清洁工作。
所以我找到了解决这个问题的方法(当我问这个问题时我几乎已经弄清楚了)但是为了澄清我会把它打出来。
由于某些原因,iOS8 中的 SpriteKit 在切换场景时不会从 Player 精灵中移除烟雾发射器。这不知何故导致崩溃,因为它出于某种原因试图在下一个场景中对其执行一些逻辑。
我上面的几乎是正确的。首先使用粒子发射器子项的 removeFromParent() 方法覆盖精灵
// Sprite with ParticleEmitterNode child attached to it's method
override func removeFromParent() {
self.deathSmokeEmitter?.removeFromParent()
super.removeFromParent()
}
在切换场景之前,只需执行 spriteWithEmitterChild.removeFromParent() 从场景中移除精灵(将发射器作为子画面),这将调用覆盖的方法并从精灵中移除烟雾发射器 BEFORE从场景中移除精灵。