The duration
property for moveTo
isn't followed when inside a runBlock
, allowing the subsequent action in a sequence to get executed immediately when it should only get executed after duration
seconds.
Code A (sequence properly executed):
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()
}]))
Code B (sequence not properly executed):
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()
}]))
In Code A
, itemB
gets removed after the moveAction
completes (about 2 seconds). This is the correct sequence.
In Code B
, itemB
gets removed before badMoveAction
finishes, meaning itemB
never moves from its original position. It's as if the duration property isn't honored in Code B
.
How can we move itemB
as in Code B
but ensure the next action in the sequence doesn't start until badMoveAction
completes?
This should do what you want. i just re-arranged the code a little bit.
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()
})
})
]))
EXPLANATION: When you execute a block of code, it is executed asynchronously. This means the code will be executed on a separate queue while the rest of your code continues to execute.
In the case of Code A this does not cause an issue because the moveTo action is run on the current queue, completed and then the runBlock is fired.
In the case of Code B this creates an issue because the badMoveAction block is fired, it begins executing on a separate queue and the code continues on to the next piece which happens to be the remove action that removes itemB, while the badMoveAction was executing in the background. If you did something else in that runBlock you will see them run simultaneously, but because you removed it, everything is removed.
Solution If you are saying you want to add badMoveAction to a node and have that calculate every time you could do something like this:
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()
}
*Code is just for example of what you can do to resolve this issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With