关闭 SKScene 回到 UIKit 菜单
dismiss SKScene go back to UIKit Menu
一旦我的 SpriteKit 游戏结束,我想回到我的 UIKit MenuViewController
。根据我到目前为止所学到的,使用 protocol/delegate 是最好的(?)选项,但我没能让它工作。我知道该协议可能会超出 GameViewController
的 class 声明,看起来像:
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 可以访问它。在这个例子中,它是玩家的数量。
我同意 Whirwind 的评论:当您可以使用一个 viewController 来完成所有游戏时,为什么还要混合两种不同的框架并使您的生活变得复杂?
无论如何,根据你的故事板截图,有 2 个 viewController,你只能转到第二个 viewController(和 GameScene
)如果你按下一个按钮。
有两件事要做:释放当前的 SKScene(在您的情况下是 GameScene
)并呈现 "initial view controller" 或您的 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")
}
}
输出:
一旦我的 SpriteKit 游戏结束,我想回到我的 UIKit MenuViewController
。根据我到目前为止所学到的,使用 protocol/delegate 是最好的(?)选项,但我没能让它工作。我知道该协议可能会超出 GameViewController
的 class 声明,看起来像:
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 可以访问它。在这个例子中,它是玩家的数量。
我同意 Whirwind 的评论:当您可以使用一个 viewController 来完成所有游戏时,为什么还要混合两种不同的框架并使您的生活变得复杂?
无论如何,根据你的故事板截图,有 2 个 viewController,你只能转到第二个 viewController(和 GameScene
)如果你按下一个按钮。
有两件事要做:释放当前的 SKScene(在您的情况下是 GameScene
)并呈现 "initial view controller" 或您的 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")
}
}
输出: