I had same problem. Here is my solution.
/// 190926: NodeAction is node bound with an action but waiting for a comletion argument to be given
public typealias NodeAction = (_ completion: @escaping () -> Void) -> Void
extension SKNode { // 190926
public func doAction(_ action:SKAction) -> NodeAction {
let actionWithCompletion = { [weak self] (completion:@escaping () -> Void) in
guard let this = self else { return }
this.run(action, completion: completion)
}
return actionWithCompletion
}
public static func execute(nodeActions:[NodeAction]) {
if let nodeAction = nodeActions.first {
let rest = Array(nodeActions.dropFirst())
nodeAction { execute(nodeActions: rest) }
}
}
}
To do what you want:
let arrayOfNodes:[SKNode] = []
let positionToMove = CGPoint(x: 400, y: 400)
var nodeActions:[NodeAction] = []
for node in arrayOfNodes {
nodeActions.append(node.doAction(SKAction.wait(forDuration: 5)))
nodeActions.append(node.doAction(SKAction.move(to: positionToMove, duration: 1.0)))
}
SKNode.execute(nodeActions: nodeActions)
I also the following additional idea which I have not tested:
extension SKNode {
func doActionBlock(_ block: @escaping () -> Void) -> NodeAction { // 190322 give this a try ???
let action = SKAction.run(block)
let actionWithCompletion = { [weak self] (completion:@escaping () -> Void) in
guard let this = self else { return }
this.run(action, completion: completion)
}
return actionWithCompletion
}
}
Of course, you don't have to use it just for an array. In general, you declare "var nodeActions:[NodeAction] = [ ]" and then add the actions you want to happen. Since "node" is usually just the scene, you can omit it.
Here is an example where I am doing a demo of leading a card in a game:
var nodeActions:[NodeAction] = []
nodeActions.append(doAction(SKAction.wait(forDuration: DemoThinker.demoThinkingDuration)))
if shouldKibitz {
nodeActions.append(doAction(SKAction.kibitzAction(gameEvent: gameEvent, gameScene: self)))
}
nodeActions.append(doAction(SKAction.demoLeadCardEventAction(for: gameEvent, gameScene: self, cardNode: cardNode)))
nodeActions.append(doAction(SKAction.unhighlight(node: cardNode)))
nodeActions.append(doAction(SKAction.setupDragPileNode(cardNode: cardNode, gameScene: self)))
nodeActions.append(doAction(SKAction.faceup(cardNode: cardNode, faceup: true)))
nodeActions.append(dragPileNode.doAction(SKAction.group([highlightWhenDiscardingAction, moveToAction]))) /// moveTo action)
nodeActions.append(doAction(SKAction.wait(forDuration: didDiscardDropWaitTime)))
nodeActions.append(doAction(SKAction.removeDemoBubbleNodeAction(gameScene: self)))
nodeActions.append(doAction(SKAction.removeYellowDotAction(player: player, gameScene: self)))
nodeActions.append(doAction(SKAction.unhighlightDiscardPileOutlineNode(player: player, gameScene: self)))
nodeActions.append(doAction(SKAction.demoRestHandleLeadCardEvent(for: gameEvent, gameScene: self)))
SKNode.execute(nodeActions: nodeActions)