【问题标题】:Difference between GameViewController and SKScenesGameViewController 和 SKScenes 的区别
【发布时间】:2016-08-25 18:00:01
【问题描述】:

我一直在使用 SpriteKit 和 Swift 开发游戏,但我似乎无法确定 GameViewController 和我的任何一个 SKScenes 之间的真正区别是什么。我试图理解这些差异,因为我想在我的游戏中实现一个 GameCenter 或本地排行榜,但是在我找到的所有教程中(比如这个:Game Center Leaderboards!(Xcode 中的 Swift 2))它们都有所有的逻辑GameViewController 因为他们正在使用单视图应用程序。当我阅读文档时,我无法理解这种关系,所以任何帮助都会很棒。最终,我希望能够在我的一个场景(例如GameOverScene)中向 GameCenter 显示和推送数据。感谢您的帮助!

【问题讨论】:

  • 这实际上是一个很好的问题,很多人似乎还没有完全理解,你应该在 SO:Documentation 提出这个问题

标签: swift uiviewcontroller sprite-kit gamekit game-center-leaderboard


【解决方案1】:

这里有一些很好的信息:

SK 中每一帧发生的情况示意图:


所以你看,SKScene 是一个包含所有有趣的东西的类,比如节点和动作,并且是所有(对你很重要的)事情发生的地方。您可以通过编辑器生成这些场景,但是您可能需要创建一个新的 .swift 文件来配合它(因为每个场景都可以有自己的逻辑)。

编辑器只是初始化一堆东西的“捷径”,老实说,你可以用很少的代码制作完整的游戏(但你很快就会发现你想要更多) p>

因此,在这段代码中,您声明 GameScene 或 PauseScreen(它们基本上只是类声明,从 SKScene 继承),您很快就会发现这行在谈论 ISNT 场景:

override func didMoveToView(view: SKView) .. 它正在调用 SKView... 那是什么,它是从哪里来的?

(在此处了解 SKView,并查看其继承):

https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKView/index.html#//apple_ref/occ/cl/SKView


我们在GameViewController 文件中找到了这个 SKView 声明(它只是一个类),请注意它与大多数常规 iOS 应用程序相同,因为它继承了 UIViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    if let scene = GameScene(fileNamed:"GameScene") {
        // Configure the view.
        let skView = self.view as! SKView
        skView.showsFPS = true
        skView.showsNodeCount = true

        /* Sprite Kit applies additional optimizations to improve               rendering performance */
        skView.ignoresSiblingOrder = true

        /* Set the scale mode to scale to fit the window */
        scene.scaleMode = .AspectFill

        skView.presentScene(scene)
    }

同样,该方法在 GameViewController.swift 中声明,基本上就是这样: class GameViewController: UIViewController


那么所有这些与 iOS 应用程序和 SpriteKit 有什么关系呢?好吧,它们都被捣碎了:

IOS 应用剖析:

基本上,从右到左,你有一个窗口,它是(如果错了,请纠正我)AppDelegate,然后是 ViewController,然后是你的视图,其中包含所有很酷的东西(故事板位于视图内,就像 SKScenes 位于 View 内部一样......标签、节点或按钮,都位于它们各自的类中((视图)))

这都是继承的大三明治。


查看 Apple 网站了解更多信息。

https://developer.apple.com/library/safari/documentation/UserExperience/Conceptual/MobileHIG/ContentViews.html#//apple_ref/doc/uid/TP40006556-CH13-SW1

https://developer.apple.com/spritekit/

https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SpriteKitFramework_Ref/

https://developer.apple.com/library/safari/documentation/UserExperience/Conceptual/MobileHIG/Anatomy.html

基本上,一切都是从类继承的类,等等,等等......它可能会变得混乱。你也可以在 Xcode 中通过 CMD+点击它们来查看这些继承,这将跳转到源文件。

祝你在 SpriteKit 的学习和冒险顺利:)

【讨论】:

  • 你没有抓住问题的重点,你解释了场景和视图,但你没有解释视图控制器和场景的区别
  • @Knight0fDragon,我一直在进行一些编辑,因为我发现我遗漏了一些信息。请检查我的更新,让我知道你的想法。
  • 我认为 OP 需要评论来改进这个答案,很难说出他到底在寻找什么。
  • @knight0fDragon 今天早些时候我一直在帮助他处理他的其他文件,在那里他进行了更详细的解释:stackoverflow.com/questions/39149404/… 在其中,我具体展示了控制器如何与场景交互。我觉得我在这方面的能力不够强,无法给出详尽的答案,因为我自己还是新手。我试图提供资源(即使我是 IRL 导师)我不想解释,然后发现我犯了一个大错误。
  • 好吧,看来他真的需要开始学习一些教程,逐步了解 Sprite Kit 中的工作原理
【解决方案2】:

您的游戏中应该只有一个 GameViewController。 SKScene 是游戏在 to 之间转换的场景。

例如,主菜单屏幕?那是一个SKScene。主要玩法?那是一个SKScene。游戏结束画面?那是一个 SKScene。

GameViewController 初始化了游戏将在其中维护的整个视图,因此视图。 SKScene 只是放置在视图顶部的场景。您应该查看使用 SKScenes 的教程。

这是使游戏中心从最新的 Swift 2.2 开始工作的方法。

将此函数添加到 GameViewController 类中的任何位置,然后在 super.viewDidLoad() 之后立即调用它。

func authenticateLocalPlayer() {
    let localPlayer = GKLocalPlayer.localPlayer()
    localPlayer.authenticateHandler = {(viewController, error) -> Void in

       if (viewController != nil) {
            self.presentViewController(viewController!, animated: true, completion: nil)
        }
        else {
            print((GKLocalPlayer.localPlayer().authenticated))
        }
    }
}

在您的 SKScene 类文件中添加以下函数。不要忘记导入 GameKit。只要您想显示排行榜,只需调用 showLeader()。

func showLeader() {
    let viewControllerVar = self.view?.window?.rootViewController
    let gKGCViewController = GKGameCenterViewController()
    gKGCViewController.gameCenterDelegate = self
    viewControllerVar?.presentViewController(gKGCViewController, animated: true, completion: nil)
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController) {
        gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}

这是我如何将分数保存到游戏中心的示例。

func saveHighscore(gameScore: Int) {
    print("Player has been authenticated.")
    if GKLocalPlayer.localPlayer().authenticated {
        let scoreReporter = GKScore(leaderboardIdentifier: "YOUR_LEADERBOARD_ID")
        scoreReporter.value = Int64(gameScore)
        let scoreArray: [GKScore] = [scoreReporter]

        GKScore.reportScores(scoreArray, withCompletionHandler: {error -> Void in
        if error != nil {
            print("An error has occured: \(error)")
        }
        })
    }
}

【讨论】:

  • 如果此方法在我的GameOverScene 内,self 应在gKGCViewController.gameCenterDelegate = self 行中引用什么?我收到错误 Cannot assign value of type GameOverScene to type GKGameCenterControllerDelegate? ?
  • 将 GKGameCenterControllerProtocol 添加到 SKScene 类。确保函数 showLeaderboard() 在 SKScene 类中,因为 self 指的是类对象的实例。
  • @Sam,我将整个代码放在您开始的另一个问题上。它也包括 GK 的东西:P
  • @jozemiteApps 非常感谢,我现在才开始工作,但分数没有更新——我不能在场景的 viewdidload 中调用 saveHighScore 吗?我也收到此错误:Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UIAlertController: 0x1489d2190>)
  • 不,你为什么要在玩家还没玩的时候在 viewDidLoad 中调用它呢? saveHighScore 的目的是在用户获得新的高分时保存分数,对我来说,这在游戏结束函数中被调用。至于错误,我总是明白,但游戏中心仍然可以 100% 工作。这意味着视图在加载时试图自行卸载。听起来这是一个我从来没有费心去实现的协议功能。函数gameCenterViewControllerDidFinish()是GameKit自己调用的协议函数,不是我自己调用的。可能是不需要添加的功能之一。
【解决方案3】:

这完全取决于您如何设计您的应用,以及您想使用什么技术。

如果您希望在 100% Sprite Kit 中构建应用程序,那么您将 UIViewController 视为包含 Sprite Kit 应用程序的外壳。只有当您需要做 SpriteKit 场景不应该做的事情时,您才应该触摸它,例如创建手势控件等等。

但是,拥有多个带有 sprite kit 元素的视图控制器是有用途的。也许您正在制作一个业务应用程序,并决定在其中包含一个小游戏。

IMO 在网页设计方面考虑它的最佳方式是将您的视图控制器视为您的 HTML 页面,并将您的场景视为您嵌入网站的 flash/silverlight/unity/etc 游戏播放器。有时您希望该播放器全屏显示,有时您不希望,这取决于应用程序的设计。全屏时,我们不需要任何其他组件,因此播放器可以完成所有工作。但是,如果我们在页面上附加一个如何引导链接怎么办。我们不希望在游戏中这样做,我们希望在游戏之外这样做。该链接随后会打开一个新页面,与旧页面无关,并且对游戏玩家组件没有任何用处。

现在对于您使用 Game Center 的情况,情况变得更加复杂。 Game Center 是在 Sprite Kit 出现之前构建的,因此它的所有功能都建立在 UIKit 之上。但 Game Center 也允许自定义,因此您不必使用它的 UIKit 功能。当然,您必须完成所有工作,然后使用 Sprite Kit 对象在场景中显示信息。

为了让您的生活更轻松,您需要将所有需要的内置代码包含到您的视图控制器中,然后您要做的就是创建一个场景知道的委托,并将您的视图控制器分配给这个委托。现在 Game Scene 可以访问您允许的该视图控制器的任何元素,例如显示排行榜或传递排行榜。完整查看本教程,它将帮助您了解实现所需目标所需的一切。 https://www.raywenderlich.com/115300/swift-2-tutorial-part-3-tuples-protocols-delegates-and-table-views

【讨论】:

    【解决方案4】:

    在 MVC 中,控制器充当协调器,有点像管弦乐队中的指挥。我的偏好是场景只做他们设计的一件事,即实现游戏。当一个场景完成时,最后的任务是通知控制器(使用委托模式)场景已经完成。然后由控制器决定接下来会发生什么,即过渡到下一个场景或游戏结束。

    【讨论】:

    • 实际上控制器不应该告诉场景做什么,指挥是视图控制器,视图是管弦乐队中的音乐家,你的场景是乐器。视图控制器应该告诉视图正在发生转换,并且视图应该告诉场景它正在发生变化,与您试图获得的概念相同,只是更详细。
    • 我喜欢这样的想法,即场景只做一件事,对游戏的大局一无所知。这就是使用软件类比的 SOLID(单一职责)中的 S。 GameViewController 的工作是按照正确的顺序呈现场景并从用户离开的地方重新开始等等。
    • 它不应该,我只是说 MVC 在其简单格式中不能 100% 工作,因为 SKView 必须是中间体
    • @JozemiteApps,这不是真的,这是一种实际上适用于 MMO 的模式(您告诉服务器要做什么(模型),服务器会向您显示您应该看到的内容),在 Sprite 套件中可以正常工作
    • 我们可以就这类东西进行长达一年的辩论,但不能安全地假设它因为技术原因而不起作用,然后到处传播给那些无法独立思考的人。您需要始终问自己,将特定模式用于特定应用程序是否有意义,然后应用该技术,而不是相反
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 2011-10-20
    • 2020-01-23
    • 1970-01-01
    相关资源
    最近更新 更多