在两个或多个SKSpriteNode上同步SKActions?

时间:2014-01-05 16:10:33

标签: ios objective-c xcode sprite-kit

我希望同步移动两个(或更多)SKSpriteNode个。任何差异都会显示出来我尝试按顺序触发每个精灵的SKAction,当最后一个精灵完成时,它会触发一个新的动作。但事实证明,这些动作并没有以它们开始的相同顺序结束,这导致了一个明显的时间差异。

有没有办法在两个或多个具有持续时间的精灵上运行并行SKActions,以便它们在完全相同的时间结束,或者至少按照它们的开始顺序结束?

这是一个不起作用的原则示例:

- (void)testMethod1{
SKSpriteNode *child_1=[arrayWithSprites objectAtIndex:1];
SKSpriteNode *child_2=[arrayWithSprites objectAtIndex:2];

//This doesn't work.
[child_1 runAction:[SKAction moveToX:20.0 duration:0.5]];
[child_2 runAction:[SKAction moveToX:20.0 duration:0.5] 
    completion:^{[self testMethod1];}];
//Actions might not be finished in the order they are started.
}

这是我尚未尝试的一种方式,但想知道它是否可以解决我的问题:

- (void)testMethod2{
SKSpriteNode *child_1=[arrayWithSprites objectAtIndex:1];
SKSpriteNode *child_2=[arrayWithSprites objectAtIndex:2];

//Will this guarantee total syncronisation?
[self runAction:[SKAction group:[NSArray arrayWithObjects:
                                 [SKAction runBlock:^{[child_1 runAction:[SKAction moveToX:20.0 duration:0.5]];}],
                                 [SKAction runBlock:^{[child_2 runAction:[SKAction moveToX:20.0 duration:0.5]];}],
                                 nil]]
      completion:^{[self testMethod2];}];
}

我希望我的英语和想法是可以理解的。

// Micke ....

3 个答案:

答案 0 :(得分:4)

只需添加一个容器SKNode,然后它们就会立即移动:

SKNode *containerNode = [[SKNode alloc] init];    
[containerNode addChild:node1];    
[containerNode addChild:node2]; //add as many as necessary    
[containerNode runAction:someAction]; //declare the action you want them both to perform

答案 1 :(得分:4)

泰勒的解决方案非常有效。

但如果您不能或不想这样做,您应该知道很可能的动作是多线程的,因此它们可以按任何顺序完成,但它们仍应在同一帧中完成。

为了确保它们在运行testMethod之前都运行完成,您应该在didEvaluateActions中执行代码。然后你需要找到一种方法来弄清楚两个动作是否都已完成。一种方法是使用密钥。

[child_1 runAction:[SKAction moveToX:20.0 duration:0.5] withKey:@"action1"];
[child_2 runAction:[SKAction moveToX:20.0 duration:0.5] withKey:@"action2"]; 

然后通过检查这些操作是否仍然存在来检查这两个操作是否已完成:

-(void) didEvaluateActions
{
    if ([child_1 actionForKey:@"action1"] == nil && 
        [child_2 actionForKey:@"action2"] == nil)
    {
        // both actions have ended, start new ones here ...
    }
}

或者,您可以使用两个操作都运行的完成块。增加NSUInteger计数器变量并在块中将计数器增加1,然后测试计数器的值是否等于(或大于)并发操作数。如果是,您知道两个操作都已完成:

__block NSUInteger counter = 0;
void (^synchBlock)(void) = ^{
    counter++;
    if (counter == 2)
    {
        [self testMethod1];
    }
};

[child_1 runAction:[SKAction moveToX:20.0 duration:0.5] completion:synchBlock];
[child_2 runAction:[SKAction moveToX:20.0 duration:0.5] completion:synchBlock]; 

答案 2 :(得分:0)

你的帧率是否恒定?您的第一个示例在技术上应该有效,但完成顺序可能基于其他内容,例如它们的绘制顺序。

您可以采用的一个概念是将它们临时封装在容器节点中,然后通过操作仅移动容器节点。操作完成后,将其从容器中移除并返回其原始父级。

您是否发现它们在视觉上不同步?或者你的testMethod1在某种程度上要求两个动作都完成了吗?

虽然我建议的容器概念适用于您的具体示例,但它不是一个有效的选项,除非希望对象像连接一样移动。容器无法工作的一个例子是每个对象是否必须在1秒内移动到不同的位置。