解雇SKScene回到UIKit菜单

时间:2017-04-11 04:28:57

标签: ios swift sprite-kit skscene

一旦我的SpriteKit游戏结束,我想回到我的UIKit MenuViewController。根据我迄今为止所学到的知识,使用 协议/代理 是最好的(?)选项,但我还没有达到目的工作。我知道协议可能会超过GameViewController的类声明,看起来像:

protocol GameViewControllerDelegate {
    var gameOver: Bool?
}

但是我需要帮助从GameScene访问它并让它解雇GameViewController。以下是应用程序的骨骼,如果有帮助的话。

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

    }
...

这款SpriteKit游戏有一个MenuViewController,一个GameViewController和一个GameScene。当您从MenuViewController按下按钮时,数据将通过segue发送到GameViewController。在GameViewController呈现GameScene之前,它将数据存储在场景的userData变量中,以便GameScene可以访问它。在这个例子中,它是玩家的数量。

1 个答案:

答案 0 :(得分:4)

我同意Whirwind的评论:为什么当你只使用一个viewController来完成你的所有游戏时,混合两个不同的框架并使你的生活变得复杂?

无论如何,根据你的故事板截图,有2个viewControllers,只有按下按钮,你才可以转到第二个viewController(和GameScene

有两件事要做:取消分配当前的SKScene(在您的情况下为GameScene)并显示“初始视图控制器”或您的MenuViewController

为此,我使用“Hello world” Sprite-kit模板和协议/委托方法来扩展SKSceneDelegate {{3} }。如您所见,我们可以解除场景(呈现无)并在GameViewController上调用外部方法以显示MainViewController

为了确保这两项操作都取得成功,我还使用两个print进行调试:

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

<强>输出

class