在发生runBlock(Swift)后,延迟SKAction.sequence中的下一个动作?
在runBlock
内部不会遵循moveTo
的duration
属性,从而允许序列中的后续操作在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 A
, itemB
在moveAction
完成后被移除(大约2秒)。 这是正确的顺序。
在Code B
, itemB
在badMoveAction
完成之前被移除,这意味着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
应该延迟块足够长的时间,以便块内的操作完成后运行。