Nicholas
Nicholas

Reputation: 1935

dismiss SKScene in SpriteKit and Swift

While my game is paused I managed to open another view for info/credits/settings as

let block = SKAction.runBlock {
    let myScene = CreditsScene(size: self.size)
    myScene.scaleMode = self.scaleMode
    self.view?.presentScene(myScene)
}
self.runAction(block)

When the CreditsScene opens I can tap on the scene to go back to the paused game. However no matter how I try I cannot go back :(

At the moment the best I did is like

let block = SKAction.runBlock {
    let myScene = GameScene(size: self.size)
    myScene.scaleMode = self.scaleMode
    self.view?.presentScene(myScene)
}
self.runAction(block)

which in my opinion opens a NEW GameScene and not the previous one. I also tried removeFromParent, presentScene(nil), but none of them work.

Do you have other better ideas? Thanks

Upvotes: 2

Views: 1734

Answers (1)

rickster
rickster

Reputation: 126167

You're presenting a new GameScene because you're creating a new GameScene. If you want to keep the GameScene instance you were using and return to it, you'll need to present that instead. Either that, or you'll need a way for your GameScene class to save and restore its state, so that a new instance of it can be restored to replicate whatever was going on in the old instance.


For the first option, you could do something like this:

// in GameScene
let block = SKAction.runBlock {
    let credits = CreditsScene(size: self.size)
    credits.returnToScene = self    // add this property to CreditsScene
    credits.scaleMode = self.scaleMode
    self.view?.presentScene(credits)
}
self.runAction(block)

// in CreditsScene
let block = SKAction.runBlock {
    self.view?.presentScene(self.returnToScene)
}
self.runAction(block)

Here, you're passing a reference to the current GameScene to your CreditsScene, so that the CreditsScene knows what GameScene to return to once it's done. Alternatively, you could store a reference to the current GameScene in some place that's global (relative to the scenes, at least), like a view controller.


For the other option, you'll need to make sure that all the state in your GameScene class (or at least all the state that's meaningful to the player) can be saved and restored: current score, current player position, where the enemies are and what they're doing, etc... whatever your game does. SpriteKit classes already support NSCoding, so this is a good way to handle saving/restoring — just make sure that any custom subclasses of yours (like GameScene) encode whatever state they have.

Then, you can archive off your GameScene when transitioning away, and restore from that archive when you're ready to return. That'd look something like this:

// in GameScene
let block = SKAction.runBlock {
    let credits = CreditsScene(size: self.size)
    credits.returnToScene = self    // add this property to CreditsScene
    credits.scaleMode = self.scaleMode

    let sceneData = NSKeyedArchiver.archivedDataWithRootObject(self)
    sceneData.writeToFile(savedGamePath, atomically: true)

    self.view?.presentScene(credits)
}
self.runAction(block)

// in CreditsScene
let block = SKAction.runBlock {
    if let game = NSKeyedUnarchiver.unarchiveObjectWithFile(savedGamePath) {
        self.view?.presentScene(game)
    }
}
self.runAction(block)

(This presumes savedGamePath is a constant accessible to both classes.)


By the way, if your use of SKAction.runBlock here reflects what's actually in your game (as opposed to a simplification of your code for purposes of this SO question), it's redundant. You don't need to create a runBlock action for code you're going to run immediately. So, unless you actually need to stash that action for running later, you can simplify my first solution above down to something like this:

// in GameScene
let credits = CreditsScene(size: self.size)
credits.returnToScene = self    // add this property to CreditsScene
credits.scaleMode = self.scaleMode
self.view?.presentScene(credits)

// in CreditsScene
self.view?.presentScene(self.returnToScene)

Upvotes: 4

Related Questions