Why has the termination never been called?
I'm terribly sorry about this, a dump of code ... because I have no idea why every part of this works, except for a call to completion.
SKAction, which does not cause its completion, all but completion. It:
curtain.run(fadeMoveWipeAndReveal, completion: {onDone(), print("I'm done!!!!")})
In the following class:
import SpriteKit class WipeCurtain: SKSpriteNode { var wipeCurtainBase: SKSpriteNode? var returnable = SKNode() var moveRight = SKAction() var node = SKNode() init( color: SKColor, size: CGSize, time: TimeInterval, reveal: @escaping () -> (), onDone: @escaping () -> ()) { super.init(texture: nil, color: color, size: size) wipeCurtainBase = SKSpriteNode(color: color, size: size) let show = SKAction.run(reveal) let fadeIn = createFadeIn(duration: time) let moveRight = createMoveRight(duration: time) let wipeRight = createWipeRight(duration: time) let fadeAndMove = SKAction.group( [ fadeIn, moveRight ] ) let wipeAndReveal = SKAction.group( [ show, wipeRight ] ) let fadeMoveWipeAndReveal = SKAction.sequence( [ fadeAndMove, wipeAndReveal ] ) if let curtain = self.wipeCurtainBase { curtain.anchorPoint = CGPoint(x: 1, y: 0) curtain.position = CGPoint(x: frame.size.width, y: 0) curtain.zPosition = -1 curtain.name = "wipe" curtain.run(fadeMoveWipeAndReveal, completion: { onDone() print("I'm done!!!!") }) } } func createFadeIn(duration: TimeInterval) -> SKAction { let fadeIn = SKEase .fade( easeFunction: .curveTypeLinear, easeType: .easeTypeIn, time: duration, fromValue: 0, toValue: 1 ) return fadeIn } func createMoveRight(duration: TimeInterval) -> SKAction { let moveRight = SKEase .move( easeFunction: .curveTypeExpo, easeType: .easeTypeOut, duration: duration, origin: CGPoint( x: 0, y: 0), destin: CGPoint( x: frame.size.width, y: 0) ) return moveRight } func createWipeRight(duration: TimeInterval) -> SKAction { let wipeRight = SKEase .createFloatTween( start: 1, ender: 0, timer: duration, easer: SKEase .getEaseFunction( .curveTypeExpo, easeType: .easeTypeOut ), setterBlock: {(node, i) in node.xScale = i} ) return wipeRight } func wipeWith() -> SKNode { if let curtain = wipeCurtainBase?.copy() as! SKSpriteNode? { returnable = curtain } return returnable } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
Update:
Here's the gameScene that does this job, a very easily modified version of the Xcode SpriteKit template:
import SpriteKit import GameplayKit class GameScene: SKScene { private var swipe: WipeCurtain? override func didMove(to view: SKView) { swipe = WipeCurtain(color: .brown, size: frame.size, time: 1, reveal: self.showOrNot, onDone: self.previewer ) } func showOrNot(){ print(" Deciding to show or not.......") } func previewer(){ print("now running the previewer") } func touchDown(atPoint pos : CGPoint) { addChild(swipe!.wipeWith()) } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for t in touches { self.touchDown(atPoint: t.location(in: self)) } } }