How can I transition between scenes without my game resetting because didMoveToView()
was called and reinitialized all of my instance variables. For example I have a game scene and a shop scene. When I transition from my shop scene to my game, the game resets. Is there a way to prevent this or how do I keep the same state of my game when transitioning between scenes?
You have lots of options to keep persistent state across your game scenes. I've listed two approaches I've used.
Option A: Maintain a Reference to the Scene
When a scene is swapped out for a new one, the scene is often fully removed from memory. If you hold onto a reference for the scene object somewhere else, and present that reference, no data will be lost.
To maintain a reference over time (and present the scene again when needed), I recommend a scene presenter class with a static instance such as the following:
class SceneCoordinator {
static var shared = SceneCoordinator()
var gameScene : GameScene?
var shopScene : ShopScene?
}
when you initialize a GameScene
, also register it with your with SceneCoordinator.shared.gameScene = self
. Then, when transitioning away from another scene, you can present the instance you stored in the coordinator class.
didMoveToView()
will still be called on the scene when it is presented again. You could move all your initializing code to a separate function, create a new instance var such as var isInitialized = false
, and only initialize your content if it is false (and set it to true after your initialize).
The issue with this approach is that scene objects are expensive, which means you could build up a large overhead by not allowing scenes to be released.
Option B: Model Struct
The better way (which would also allow for easier reinit of a scene after your app closes) would be to create a data model of your game state, and provide a function to create a GameScene from your model object.
This method is more consistent with the Model-View-Controller design pattern, and allows your scenes and data to be a lot more lightweight.
Such as:
struct GameModel {
var coins : Int
}
class GameScene : SKScene {
var state : GameModel
convenience init(size: CGSize, state: GameModel) {
self.state = state
// set up scene content from state
}
// lots of fun game scene logic
func playerCollectedCoin() {
state.coins += 1
}
func moveToShopScene() {
// init a new shop scene with the state of this scene
let shop = ShopScene(size: self.view!.bounds.size, state: self.state)
(self.view as! SKView).presentScene(scene)
}
}
class ShopScene : SKScene {
var state : GameModel
convenience init(size: CGSize, state: GameModel) {
self.state = state
// set up scene content from state
}
// lots of fun shop scene logic
func playerSpentCoins(amount: Int) {
state.coins -= amount
}
func moveToGameScene() {
// init a new game scene with the updated state of this scene
let game = GameScene(size: self.view!.size, state: self.state)
(self.view as! SKView).presentScene(game)
}
}