在 runBlock 发生后延迟 SKAction.sequence 中的下一步操作 (Swift)?
Delay next action in SKAction.sequence after runBlock occurs (Swift)?
moveTo
的 duration
属性 在 runBlock
中不被遵循,允许序列中的后续动作在它应该只执行时立即执行在 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
完成之前不会开始?
您需要更改 runAction
的来电者。使用 self
来调用它。因为您正在使用 runBlock
并且您说 parasite
运行其中的操作,所以不需要调用 parasite
上的函数。所以这样称呼它:
self.runAction(SKAction.sequence([SKAction.waitForDuration(0.5), moveParasite]))
解释:
当您执行一段代码时,它是异步执行的。这意味着代码将在单独的队列上执行,而其余代码将继续执行。
在 代码 A 的情况下,这不会导致问题,因为 moveTo 操作在当前队列上 运行 完成,然后 运行块被解雇。
在 代码 B 的情况下,这会产生一个问题,因为 badMoveAction 块被触发,它开始在一个单独的队列上执行,代码继续到下一个发生的部分成为删除 itemB 的删除操作,而 badMoveAction 在后台执行。如果您在那个 运行 块中做了其他事情,您将同时看到它们 运行,但是因为您删除了它,所以所有内容都被删除了。
解决方案
如果你说你想添加 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()
}
*代码只是您可以采取哪些措施来解决此问题的示例。
SKAction.runBlock
的持续时间为 0.0
。幸运的是,duration
属性 是可变的。
badMoveAction.duration = 2.0
应该在块内的动作完成后将块延迟到 运行。
根据文档,runBlock 会立即执行,moveTo
的持续时间不被考虑。 代码 A 和 代码 B 的顺序都是正确的,但在后一种情况下似乎顺序不对,因为 moveTo()
持续时间不受尊重。
作为 运行 导致一个或多个操作的代码块问题的解决方案,同时尊重持续时间,请尝试此代码:
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])
}
您可以尝试替代解决方案:
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
函数中的尾随闭包是一个完成块。
这应该可以满足您的要求。我只是稍微重新安排了代码。
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()
})
})
]))
moveTo
的 duration
属性 在 runBlock
中不被遵循,允许序列中的后续动作在它应该只执行时立即执行在 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
完成之前不会开始?
您需要更改 runAction
的来电者。使用 self
来调用它。因为您正在使用 runBlock
并且您说 parasite
运行其中的操作,所以不需要调用 parasite
上的函数。所以这样称呼它:
self.runAction(SKAction.sequence([SKAction.waitForDuration(0.5), moveParasite]))
解释: 当您执行一段代码时,它是异步执行的。这意味着代码将在单独的队列上执行,而其余代码将继续执行。
在 代码 A 的情况下,这不会导致问题,因为 moveTo 操作在当前队列上 运行 完成,然后 运行块被解雇。
在 代码 B 的情况下,这会产生一个问题,因为 badMoveAction 块被触发,它开始在一个单独的队列上执行,代码继续到下一个发生的部分成为删除 itemB 的删除操作,而 badMoveAction 在后台执行。如果您在那个 运行 块中做了其他事情,您将同时看到它们 运行,但是因为您删除了它,所以所有内容都被删除了。
解决方案 如果你说你想添加 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()
}
*代码只是您可以采取哪些措施来解决此问题的示例。
SKAction.runBlock
的持续时间为 0.0
。幸运的是,duration
属性 是可变的。
badMoveAction.duration = 2.0
应该在块内的动作完成后将块延迟到 运行。
根据文档,runBlock 会立即执行,moveTo
的持续时间不被考虑。 代码 A 和 代码 B 的顺序都是正确的,但在后一种情况下似乎顺序不对,因为 moveTo()
持续时间不受尊重。
作为 运行 导致一个或多个操作的代码块问题的解决方案,同时尊重持续时间,请尝试此代码:
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])
}
您可以尝试替代解决方案:
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
函数中的尾随闭包是一个完成块。
这应该可以满足您的要求。我只是稍微重新安排了代码。
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()
})
})
]))