Why is the completion never called?
I'm terribly sorry about this, a code dump... because I have no idea why every part of this works, except for the calling of the completion.
The SKAction that's not calling its completion runs, all except for the completion. It is this:
curtain.run(fadeMoveWipeAndReveal, completion: {onDone(), print("I'm done!!!!")})
Within 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 makes this work, a very lightly modded 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)) }
}
}