iOS SpriteKit SKAction completion call not working/creating odd results

雨燕双飞 提交于 2019-12-21 21:31:05

问题


I'm trying to have a SKNode move onto the screen on command. I've set up the following SKAction chain so that 1) The node moves up and offscreen, then 2) the node moves down into a starting place, then 3) starts moving around. I've used the following code to try and implement this:

    SKAction *moveUp = [SKAction moveTo: shipIntroSpot1 duration:3.0];
    SKAction *moveDown = [SKAction moveTo:shipSpot1 duration:ship1MovementSpeed];

    [self enumerateChildNodesWithName:@"ship1" usingBlock:^(SKNode *node, BOOL *stop) {
        NSLog(@"RUNNING MOVE UP");
        [node runAction: moveUp];

        [node runAction:moveUp completion:^{
            NSLog(@"RUNNING MOVE DOWN");
            [node setHidden: NO];
            [node runAction: moveDown];
        }];

        [node runAction:moveDown completion:^{

            NSLog(@"STARTING MOVEMENT");
        }];

However, the SKActions don't appear to be firing in the correct order. I used the code so that once one step was completed, the next would start. However, the SKAction doesn't appear to move the node fast enough before the next SKAction starts working. I was under the impressions that using the completion call would mean that the next action wouldn't start until the previous one had finished? That does not appear to be the case here. In addition, if I leave a long-enough duration for step 1 (MOVING UP), it will skip over step 2 (MOVING DOWN) and start executing step 3 (STARTING MOVEMENT). I have absolutely no idea how this is possible. If anyone could point out my error in understanding how to chain different actions together properly, I would appreciate it.

(I did not do a SKAction sequence because I have to "unhide" the node halfway through. I don't think I can put that in a sequence, unless I'm wrong about that too.)


回答1:


It does not seem like you understand how runAction is executed.

Using

    [node runAction:moveUp completion:^{
        NSLog(@"RUNNING MOVE DOWN");
        [node setHidden: NO];
        [node runAction: moveDown];
    }];

will not just define a completion to be done at the end of the action, but it runs the action and then calls the completion, so the very first [node runAction:moveUp] needs to be removed.

Secondly, two runAction calls that are made in one function/block will be called simultaneously, and since you call [node runAction: moveUp], [node runAction:moveUp completion:] , and [node runAction:moveDown completion:] all in the same block, they will all be executed simultaneously.

This is the code you are looking for:

SKAction *moveUp = [SKAction moveTo: shipIntroSpot1 duration:3.0];
SKAction *moveDown = [SKAction moveTo:shipSpot1 duration:ship1MovementSpeed];

[self enumerateChildNodesWithName:@"ship1" usingBlock:^(SKNode *node, BOOL *stop) {
    NSLog(@"RUNNING MOVE UP");

    [node runAction:moveUp completion:^{
        NSLog(@"RUNNING MOVE DOWN");
        [node setHidden: NO];
        [node runAction:moveDown completion:^{

            NSLog(@"STARTING MOVEMENT");
        }];
    }];



回答2:


The completion block runs after the action is finished. So, if you want to move up, then move down, then move around, you need to write the following code:

[node runAction:moveUp completion:^{
        [node runAction:moveDown completion:^{
            NSLog(@"STARTING MOVEMENT");
        }];
    }];

What you have right now won't work because you call three runAction's in a row. You first tell it to moveUp, but then immediately override that action with another moveUp, this time with a completion block where you run moveDown. Then, you immediately override that action with a moveDown, so essentially, all you're doing is telling the node to moveDown, everything else is superfluous.




回答3:


I know it's been marked as answered but though I'd offer up an alternative.

An alternative option would be to simply sequence the Actions with just one completion handler

for example (could just be written as a one liner if you wanted):

NSArray *actions = @[moveUp, [SKAction unhide], moveDown];
SKAction *action = [SKAction sequence:actions];

then in your loop just write:

[node runAction:action withCompletion^{
        NSLog(@"STARTING MOVEMENT");
    }];

Hopefully someone will find this useful.



来源:https://stackoverflow.com/questions/20987153/ios-spritekit-skaction-completion-call-not-working-creating-odd-results

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!