【问题标题】:dismiss SKScene go back to UIKit Menu关闭 SKScene 返回 UIKit 菜单
【发布时间】:2017-04-11 04:28:57
【问题描述】:

SpriteKit 游戏结束后,我想回到我的UIKit MenuViewController。根据我目前所学到的,使用 protocol/delegate 是最好的(?)选项,但我无法让它发挥作用。我知道该协议可能会超出GameViewController 的类声明,看起来像:

protocol GameViewControllerDelegate {
    var gameOver: Bool?
}

但我需要帮助从 GameScene 访问它并让它关闭 GameViewController。以下是应用程序的基本内容,以防万一。

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

游戏场景

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 可以访问它。在这个例子中,它是玩家的数量。

【问题讨论】:

  • 你正在做的 IMO 是 UIKit 与 SpriteKit 的不必要混合。如果您在 Alessandro 的回答中做类似的事情,它当然会起作用,我不能说您不应该这样做,但这将是一种首选方式:stackoverflow.com/a/35409586/3402095 我说首选,因为这是可以看到的迄今为止在 Apple 的演示游戏中。
  • 绝对 - 混合 UIKit 和 SpriteKit 比我想象的要复杂。我的想法是我对约束很满意,我需要很多按钮,为什么不呢?现在我知道了。

标签: ios swift sprite-kit skscene


【解决方案1】:

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

无论如何,根据您的故事板屏幕截图,有 2 个视图控制器,您可以转到第二个视图控制器(以及 GameScene只有按下按钮

有两件事要做:释放当前的 SKScene(在您的情况下为 GameScene)并呈现“初始视图控制器”或您的 MenuViewController

为此,我使用 "Hello world" Sprite-kit 模板和 protocol/delegate 方法来扩展 SKSceneDelegate class。如您所见,我们可以关闭场景(呈现 nil)并在 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)
        }
    }
}

游戏场景

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

输出

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 2014-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-10
    相关资源
    最近更新 更多