Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dismiss SKScene go back to UIKit Menu

Tags:

Once my SpriteKit game has ended, I would like to go back to my UIKit MenuViewController. From what I've learned so far, using protocol/delegate is the best(?) option, but I haven't been able to get that to work. I know that the protocol would probably go above the class declaration for GameViewController, and look something like:

protocol GameViewControllerDelegate {
    var gameOver: Bool?
}

But I need help accessing that from GameScene AND getting it to dismiss GameViewController. Below are the bones of the app, in case that helps.

storyboard image

MenuViewController

class MenuViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func goToGame(_ sender: UIButton) {
        performSegue(withIdentifier: "toGameSegue", sender: sender.currentTitle)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destinationVC = segue.destination as? GameViewController {
            if let item = sender as? String {
                destinationVC.numberOfPlayers = item
            }
        }
    }
}

GameViewController

class GameViewController: UIViewController {

    var numberOfPlayers: String?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let view = self.view as! SKView? {
            if let scene = SKScene(fileNamed: "GameScene") {
                scene.scaleMode = .aspectFill

                scene.userData = NSMutableDictionary()
                scene.userData?.setObject(numberOfPlayers!, forKey: "numberOfPlayers" as NSCopying)

                view.presentScene(scene)
            }
        }
    }
...

GameScene

class GameScene: SKScene {

    var howManyPlayers: String?

    override func didMove(to view: SKView) {

        if let numPlayers = self.userData?.value(forKey: "numberOfPlayers") {
            howManyPlayers = numPlayers as? String
        }

        print(howManyPlayers!)

    }
...

This SpriteKit game has a MenuViewController, a GameViewController, and a GameScene. When you press a button from MenuViewController, data is sent via segue to GameViewController. Before GameViewController presents GameScene it stores the data in scene's userData variable so that GameScene can access it. In this example, it's the number of players.

like image 602
squarehippo10 Avatar asked Apr 11 '17 04:04

squarehippo10


1 Answers

I agree with Whirwind comment's: why mixing two different frameworks and complicate your life when you can use one viewController only to do all your game?

Anyway, according to your storyboard screenshot,there are 2 viewControllers and you can go to the second viewController (and to the GameScene) only if you press a button.

There are two things to do: deallocate the current SKScene (in your case the GameScene) and present the "initial view controller" or your MenuViewController.

To do it, I use the "Hello world" Sprite-kit template with a protocol/delegate approach to extend the SKSceneDelegate class. As you can see we able to dismiss the scene (presenting nil) and call an external method on the GameViewController to present the MainViewController

To be sure that both of these operations go to be successful I use also two print just for debug:

GameViewController:

import UIKit
import SpriteKit
class GameViewController: UIViewController,TransitionDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        if let view = self.view as! SKView? {
            if let scene = SKScene(fileNamed: "GameScene") {
                scene.scaleMode = .aspectFill
                scene.delegate = self as TransitionDelegate
                view.presentScene(scene)
            }
            view.ignoresSiblingOrder = true
            view.showsFPS = true
            view.showsNodeCount = true
        }
    }
    func returnToMainMenu(){
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        guard  let storyboard = appDelegate.window?.rootViewController?.storyboard else { return }
        if let vc = storyboard.instantiateInitialViewController() {
            print("go to main menu")
            self.present(vc, animated: true, completion: nil)
        }
    }
}

GameScene:

import SpriteKit
protocol TransitionDelegate: SKSceneDelegate {
    func returnToMainMenu()
}
class GameScene: SKScene {
    override func didMove(to view: SKView) {
        self.run(SKAction.wait(forDuration: 2),completion:{[unowned self] in
            guard let delegate = self.delegate else { return }
            self.view?.presentScene(nil)
            (delegate as! TransitionDelegate).returnToMainMenu()
        })
    }
    deinit {
        print("\n THE SCENE \((type(of: self))) WAS REMOVED FROM MEMORY (DEINIT) \n")
    }
}

Output:

enter image description here

like image 177
Alessandro Ornano Avatar answered Sep 22 '22 10:09

Alessandro Ornano