Is it safe to change SKNode method in gesture recognition method?
Apple states at https://developer.apple.com/documentation/spritekit/skscenedelegate :
Modifying SpriteKit objects outside of the given callbacks (a background queue or something else not core) can lead to concurrency related issues. Even dispatching work on the main thread asynchronously or later is risky as the close will likely be done outside of the timeframe that SpriteKit expects. If you are experiencing a segmentation fault or other type of failure occurring deep within the SpriteKit framework, there is a good opportunity for your code to modify the SpriteKit object outside of normal Callbacks.
I am using gesture recognizers to interact with sprite set objects. A simple example would be adding a SKAction to a node when the user has tapped on the object:
func tapAction(gr:UITapGestureRecognizer) {
scene.childNode(withName: "balloon")!.run(SKAction.fadeOut(withDuration: 2))
}
Even though this one "just works" at the moment, I'm afraid it doesn't work in more complex cases.
Is there a hint from Apple that this is allowed? Or do I really need to defer modification of the SpritKit object from gesture action to assigned callback?
source to share
It looks like you are safe, you are just assigning an action. This will work while updating the normal sprite set
if you have manipulated the actual object or deleted the node you run into problems. Let's say you click to remove a node. This response happens right before didContactBegin
. didContactBegin
would expect node, but alas, you removed it, so it will work.
If you want to feel safe, set up a run queue at the beginning of your update.
class GameScene : SKScene
{
public typealias Closure = ()->()
public var processOnUpdate = [Closure]()
override func update(_ currentTime: TimeInterval) {
proceseOnUpdate.forEach{$0()}
processOnUpdate = [Closure]()
....//do other stuff
}
}
//SKView Code
func tapAction(gr:UITapGestureRecognizer) {
scene.processOnUpdate.append(
{
scene.childNode(withName: "balloon")!.run(SKAction.fadeOut(withDuration: 2))
}}
}
My apologies if this doesn't work the first time, I'm not on a Mac right now to test this.
source to share