简体   繁体   中英

SpriteKit SKAction doesn't work after removing and readding a node

Been banging my head against this for a day now, and I really have no idea what's going on.

I have a very simple setup: an SKNode (let's call it base) which contains another SKNode (sub-base), as well as several SKShapeNode objects. At some time, I move one of the SKShapeNode objects (using removeFromParent) from the base node to the sub-base node. Then I apply an SKAction, which moves the node to some arbitrary position.

Except, that SKAction does not work when the SKShapeNode has been removed and added to the sub-base object. If I remove it from the sub-base, and put it back in the base, SKActions once again work.

I am completely stumped. Is there some property that gets set on a node when it's added to another node, which isn't getting properly reset when I remove it...? I can't imagine this is something that should be happening.

Any ideas would be so very welcome.

Update:

Here's some code that I can produce it with. This function is inside a subclass of SKNode. The class adds a bunch of SKShapeNodes, and it also has this other SKNode called testNode, so, without further ado:

-(void) removeThenAdd
{
    [someNode removeFromParent];

    [self.testNode addChild:someNode];

    SKAction* action = [SKAction moveTo:CGPointMake(200, 200) duration:1];

    SKNode* thatSameNodeJustAdded = [self.testNode.children objectAtIndex:0];

    [thatSameNodeJustAdded runAction:action];
}

Another update!

I just found that, if I add an SKAction to the node whilst it is sitting inside the testNode, then after that remove it from the testNode and add it back to its original parent, the action is then activated. Like, what am I missing here? This must be some kind of designed behaviour I'm just not using right..

This seems to be a bug in the SDK. I had this issue because I wanted to make advanced sprites (sprites with children, emitters, etc) in their own scene files so that I could selectively load and then add them to my scenes. I came up with a work around using NSKeyedArchiver and NSKeyedUnarchiver -- Convert the node (or parent node) to data, and then back again, and the new object is ready to be added to a scene, if it's an emitter, or has child nodes that are emitters they will all be copied through and properly re-added. Here is the extension I made for swift, works like a charm:

extension SKNode {
    // Pulling a node from one scene and putting it into another causes some problems with broken emitters :(
    // Fix here is to archive and then unarchive the node before returning
    class func nodeFromScene(nodeName : String, sceneFileName : String) -> SKNode? {
        if let scene = SKScene(fileNamed: sceneFileName), node = scene.childNodeWithName(nodeName) {
            let archive = NSKeyedArchiver.archivedDataWithRootObject(node)
            return NSKeyedUnarchiver.unarchiveObjectWithData(archive) as? SKNode
        }
        return nil
    }
}

I was also seeing this issue occur in my SpriteKit project. In my case I was removing a node from an SKScene file I'd created in the Scene Editor and adding it to my current scene.

Following some debugging it showed that the actions weren't being run at all. And upon further investigation I discovered why... it seems that when you add a node to the scene in this manner the isPaused property is set to true . Whether this is intentional or a bug I can't find out for sure.

From the docs: https://developer.apple.com/documentation/spritekit/sknode/1483113-ispaused

isPaused

If the value is true, the node (and all of its descendants) are skipped when a scene processes actions.

So in order to "fix" this issue, before running any SKActions on the node, unpause the node:

node.isPaused = false

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM