Brejuro
Brejuro

Reputation: 3541

SpriteKit transition between scenes without resetting game

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?

Upvotes: 3

Views: 805

Answers (2)

cpimhoff
cpimhoff

Reputation: 675

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)
    }
}

Upvotes: 3

Alessandro Ornano
Alessandro Ornano

Reputation: 35412

About your question I want to focus your attention to three elements:

  • 1) Models
  • 2) Shared Instance managers
  • 3) Subclassing

1) Instead of repeating everytime in your SKScene or SKNode the same shared properties (struct, vars or custom classes..) you could create a class that contain your shared properties.

2) It's very comfortable to your project to have some shared instance manager: for example a game manager (shared instance class) that have properties of all managers (shared instance classes) of your project (an example below):

  • network manager (check everytime his update method is called if WIFI/3G/LTE are available and store values)
  • audio manager (give shared properties about backgroundmusic,effect, volume...
  • notification manager (show pop-ups of any type: success, warning,error...)
  • file manager (save to file and read from file, clear dirs...)
  • etc..

also your game properties model like settings and your game vars.

3) If you need for example a rootNode in your scenes (to add elements to pause instead of another, to add object to the same anchored node, to make a background..) you can subclass to a customized SKScene that have this properties.


Some code to show how could appear your project, starting with a GameManager:

class GameManager: NSObject {
    static let sharedInstance = GameManager()
    var allProducts = Products()
}

Your GameScene Class instance can access a single instance of GameManager like this:

class GameScene: SKScene {
    let gameManager = GameManager.sharedInstance
    override func didMoveToView(view: SKView) {
       print("the current number of shoes is \(self.gameManager.allProducts.shoes)")
    } 
}

Your ShopScene Class instance can access the same single instance of GameManager like this:

 class ShopScene: SKScene {
        let gameManager = GameManager.sharedInstance
        override func didMoveToView(view: SKView) {
            print("the current number of shoes is \(self.gameManager.allProducts.shoes)")
    }  
}

Upvotes: 3

Related Questions