3
votes

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..

2
Show the transfer code and the actions you run. I can imagine that the move actions are initialized with the node's original position (and parent coordinate space) and don't update their target destination when you "reparent" the node.LearnCocos2D
I'm recreating the action, in some cases, much later after the node was reparented, so I guess it can't be that? Anyway, I put some code up.debu
When you say "it doesn't work", you need to be more specific. Do you get an error ? It doesn't move how you expect ? If so, tell us what exactly it does, so we can utilize that information. It sounds like maybe this is possibly about you using MoveTo and not expecting the SKNode to work differently because it now has a new coordinate space. 200,200 with the original parent, is likely not the same global location as with the new parent. Be more specific if you can.prototypical
Aye, I wish I could be more specific. But literally nothing happens. I put logs around the code so I can see it's running it, I get no errors, and if I do the same action when the child is back in the parent (having moved to the other SKNode, and back), it works fine. I chose 200,200 because it will be clear it's moving, as it resides at 0,0 in the testNode object. It just doesn't move, at all. Is there a way to debug the internal workings of SKActions..?debu
are you sure that same node is at index 0 in the children array?LearnCocos2D

2 Answers

0
votes

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
    }
}
0
votes

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