在发生runBlock(Swift)后,延迟SKAction.sequence中的下一个动作?

runBlock内部不会遵循moveToduration属性,从而允许序列中的后续操作在duration秒后才能被执行。

代码A(顺序执行正确):

 let realDest = CGPointMake(itemA.position.x, itemA.position.y) let moveAction = SKAction.moveTo(realDest, duration: 2.0) itemB.runAction(SKAction.sequence([SKAction.waitForDuration(0.5), moveAction, SKAction.runBlock { itemB.removeFromParent() }])) 

代码B(序列没有正确执行):

 let badMoveAction = SKAction.runBlock { let realDest = CGPointMake(itemA.position.x, itemA.position.y) let moveAction = SKAction.moveTo(realDest, duration: 2.0) itemB.runAction(moveAction) } itemB.runAction(SKAction.sequence([SKAction.waitForDuration(0.5), badMoveAction, SKAction.runBlock { itemB.removeFromParent() }])) 

Code AitemBmoveAction完成后被移除(大约2秒)。 这是正确的顺序。

Code BitemBbadMoveAction完成之前被移除,这意味着itemB永远不会从原始位置移开。 这就好像Code B的持续时间属性不受尊重。

我们如何在Code B移动itemB ,但是确保序列中的下一个动作直到badMoveAction完成才会启动?

这应该做你想要的。 我只是重新安排了一些代码。

 itemB.runAction(SKAction.sequence([ // wait for half a second SKAction.waitForDuration(0.5), SKAction.runBlock({ // after waiting half a second, get itemA's position let realDest = CGPointMake(itemA.position.x, itemA.position.y) let moveAction = SKAction.moveTo(realDest, duration: 2.0) // move to that position, after we get there, remove itemB from scene itemB.runAction(moveAction, completion: { itemB.removeFromParent() }) }) ])) 

说明:当你执行一段代码时,它是asynchronous执行的。 这意味着代码将在单独的队列中执行,而代码的其余部分将继续执行。

代码A的情况下,这不会引起问题,因为moveTo操作在当前队列上运行,完成后触发runBlock。

代码B的情况下,这会产生一个问题,因为badMoveAction块被触发,它开始在一个单独的队列中执行,代码继续到下一个碰巧是移除itemB的移除操作,而badMoveAction正在执行的背景。 如果你在runBlock中做了其他的事情,你会看到它们同时运行,但是因为你删除了它,所有东西都被删除了。

解决scheme如果您要将badMoveAction添加到节点,并且每次都可以按如下方式进行计算:

 let waitAction = SKAction.waitForDuration(0.5) let removeAction = SKAction.removeFromParent() let sequence = SKAction.sequence([waitAction, moveAction(), removeAction]) func moveAction() -> SKAction { let realDest = CGPointMake(itemA.position.x, itemA.position.y) let moveAction = SKAction.moveTo(realDest, duration:2.0) return moveAction() } 

*代码只是例如你可以做什么来解决这个问题。

你可以尝试一个替代解决scheme:

 itemB.runAction(SKAction.waitForDuration(0.5)) { let realDest = CGPointMake(itemA.position.x, itemA.position.y) let moveAction = SKAction.moveTo(realDest, duration: 2.0) itemB.runAction(moveAction) { itemB.removeFromParent() } } 

runAction函数中的尾随闭包是一个完成块。

你需要改变你的runAction的调用者。 用self来称呼它。 因为你正在使用runBlock而你说parasite在里面运行动作,所以不需要在parasite上调用这个函数。 所以这样称呼:

 self.runAction(SKAction.sequence([SKAction.waitForDuration(0.5), moveParasite])) 

根据文档runBlock立即执行, moveTo的持续时间不被尊重。 代码A代码B的顺序是正确的,但是在后一种情况下,由于moveTo()持续时间不被考虑,所以看起来好像没有顺序。

作为解决运行代码块导致一个或多个动作的问题的解决scheme,同时考虑持续时间,请尝试以下代码:

 func notSoBadMoveAction() -> SKAction { let realDest = CGPointMake(itemA.position.x, itemA.position.y) let moveAction = SKAction.moveTo(realDest, duration: 2.0) return moveAction } itemB.runAction(SKAction.sequence([ SKAction.waitForDuration(0.5), notSoBadMoveAction(), SKAction.runBlock { itemB.removeFromParent() }])) 

这段代码确实使用了整个移动的持续时间,并且可以代替runBlock的一些(但也可能不是全部)其他用途。 如果你愿意的话,这个函数也可以带参数,这样就可以成为一个更一般的生成动作的例子。

附加:这里是一个替代版本的函数,显示添加动作的可能性,并计算函数内的东西:

 func myMoveAction(pos: CGPoint, duration : NSTimeInterval) -> SKAction { let realDest = CGPointMake(pos.x, pos.y) let moveAction = SKAction.moveTo(realDest, duration: duration/4) let moveAction2 = SKAction.moveTo(CGPointMake(realDest.x/2, realDest.y/2), duration: duration * 2/4) let moveAction3 = SKAction.moveTo(realDest, duration: duration/4) return SKAction.sequence([moveAction, moveAction2, moveAction3]) } 

SKAction.runBlock的持续时间为0.0 。 幸运的是, duration属性是可变的。

badMoveAction.duration = 2.0应该延迟块足够长的时间,以便块内的操作完成后运行。