Delayed next action in SKAction.sequence after runBlock (Swift)?

The duration property for moveTo not executed if inside a runBlock , which allows the subsequent action in the sequence to start immediately when it should be executed only after duration seconds.

Code A (sequence completed correctly):

 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 completed properly):

 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 is deleted after moveAction completes (about 2 seconds). This is the correct sequence.

In Code B , itemB is deleted before itemB is complete, that is, itemB never moves from its original position. It is as if the duration property is not respected in Code B

How can we move itemB , as in Code B , but ensure that the next action in the sequence does not start until badMoveAction completes?

+6
source share
6 answers

This should do what you want. I redid the code a bit.

 itemB.runAction(SKAction.sequence([ // wait for half a second SKAction.waitForDuration(0.5), SKAction.runBlock({ // after waiting half a second, get itemA 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() }) }) ])) 
+7
source

EXPLANATION: When you execute a block of code, it runs asynchronously. This means that the code will execute in a separate queue while the rest of your code continues to execute.

In the case of Code A, this does not cause a problem, since the moveTo action is executed in the current queue, completed, and then runBlock is started.

In the case of code B, this creates a problem, since the badMoveAction block is started, it starts to execute in a separate queue, and the code continues to the next part, which is the delete action that deletes the B element, while badMoveAction was executed in the background. If you did something else in this runBlock, you will see that they run at the same time, but since you deleted it, everything was deleted.

Solution If you say you want to add badMoveAction to the node and count every time you can 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 an example of what you can do to solve this problem.

+2
source

You can try an alternative solution:

 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() } } 

A closure closure in runAction is a termination block.

+2
source

You need to change the caller runAction . Use self to call. Since you are using runBlock , and you are saying that parasite fires an action inside it, there is no need to call a function on parasite . So call it this:

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

According to the documentation, runBlock runs immediately, and the duration of moveTo not respected. Sequencing of both code A and code B is correct, but in the latter case it seems that it does not match the sequence, since the duration of moveTo() not respected.

As a solution to the problem of starting a code block that leads to one or more actions, observing the duration, try this code:

 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() }])) 

This code uses the full duration to move, and it can replace some (but maybe not all others) other uses of runBlock. If you want, the function can also take parameters and, as such, be turned into an even more general case of generating actions.

ADDITIONAL: The following is an alternative version of the function that displays the possibilities of adding actions and calculating the elements inside the function:

 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]) } 
+1
source

SKAction.runBlock has a duration of 0.0 . Fortunately, the duration property is mutable.

badMoveAction.duration = 2.0 should delay the block long enough to work after completion of the action inside the block.

0
source

Source: https://habr.com/ru/post/983570/


All Articles