Discard SKScene return to UIKit menu

Once my SpriteKit game is over, I would like to return to my UIKit MenuViewController . From what I have learned so far, using a protocol / delegate is the best (?) Option, but I have not been able to get this to work. I know that the protocol will probably go above the class declaration for GameViewController and will look something like this:

 protocol GameViewControllerDelegate { var gameOver: Bool? } 

But I need help to access this from GameScene and make it reject the GameViewController . Below are the bones of the app if this 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, GameViewController, and GameScene. When you press the button from the MenuViewController, the data is sent via segue to the GameViewController. Before the GameViewController presents a GameScene, it stores the data in the userData variable of the scene so that GameScene can access it. In this example, this is the number of players.

+5
source share
1 answer

I agree with Whirwind's comments: why mixing two different frameworks and making your life more complicated when you can use one viewController only to execute your entire game?

In any case, according to your screenshot on the storyboard, there are 2 view controllers, and you can go to the second viewController (and to GameScene ) only if you click the button .

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

To do this, I use the Hello Hello sprite template for use with the protocol / delegate to extend the SKSceneDelegate class . As you can see, we can fire the scene (representing zero) and call an external method on the GameViewController to represent the MainViewController

In order for both of these operations to be successful, I also use two print for debugging only:

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

+4
source

Source: https://habr.com/ru/post/1266567/


All Articles