architecture - SceneKit 游戏架构

标签 architecture game-engine scenekit

我正在尝试为 SceneKit iOS 游戏设计架构。我在下面展示了两个粗略的高层我当前首选想法的对象图/图表。

我目前只关注高级架构,即管理 Menu/GameLevel/Config/Paused 应用程序状态之间的转换并使应用程序数据驱动,以便它可以处理多个级别等。一旦我开始工作,然后我将讨论较低级别的架构,例如对于 GameLevel 状态,我将有一个 GameLevelModel 对象来表示实际的游戏关卡逻辑。

很高兴听到哪个看起来更有希望,有什么明显的陷阱或要避免的事情吗?

版本 A) 基于 MVC,带有自定义容器和嵌套 VC

我试图在这个版本中保持接近 MVC 范式。

应用程序的行为在其不同状态(菜单/游戏级别/配置/等)之间发生显着变化,因此我将使用永久容器 View Controller ,该 Controller 将管理/转换多个嵌套 VC,按照 Apple 的父子关系“查看 iOS Controller 编程指南”。这些实际上是整个 MVC。

因为 Apple 的容器 Controller (UINavigation-、UISplitScreen-、UITabBar-)都不适合(我需要整个屏幕),所以我将拥有一个自定义容器 VC (RootViewController),它始终有一个嵌套的子 VC。每个子 VC 的 View 将始终完全覆盖容器的 View 。子 VC 之间的转换将由 RootVC 管理并由其 StateMachine 驱动。

每个子 VC(实际上是整个 MVC)在其对应的状态变为当前状态时创建,然后在被下一个状态替换且不再需要时释放。类似于 UINavigationController 如何处理它包含的 VC。

我对这种架构的唯一担心是它看起来有点沉重。 SceneKit 看起来像是设计用于 SCNView 并在我们需要更改 3D 内容时在多个 SCNScene 之间进行转换。这也提供了更多的过渡选项。

                         --------------------------
                         |   RootViewController   |
                         --------------------------
                           |  |   |        |    |
     ------------------    |  |   |        |    |      ------------------
     | GameLevelsData |-----  |   |        |    -------|     SCNView    |
     ------------------       |   |        |           ------------------
     ------------------       |   |        |
     |   PlayerData   |--------   |        |
     ------------------           |        |
                                  |        |
                       ----------------    |
                       | StateMachine |    |
                       ----------------    |
                         |                 |
                         |-(*MenuState)    |
                         |-(LevelState)    |
                         |-(ConfigState)   |
                                           |
                                           |
                         ------------------------
                         |  MenuViewController  |
                         ------------------------
      -----------------     |                |      ------------------
      |   MenuData    |------                -------|  MenuSCNView   |
      -----------------                             ------------------

   (child VCs for other States, Level-/Config-/etc are created as needed)
                                           |
                         ------------------------
                         |  LevelViewController |
                         ------------------------
     ------------------     |                |      ------------------
     | GameLevelModel |------                -------|  LevelSCNView  |
     ------------------                             ------------------

版本 B) 基于场景(一个 VC,多个场景)

我将只有一个 View Controller (GameViewController) 及其 View (SCNView),它们将持续整个应用程序生命周期。
(我将 而不是 在这里有容器和嵌套的 VC。)

应用程序状态(Menu/GameLevel/Config/etc)之间的行为和内容的变化是通过场景和不同 TouchHandlers(每个状态的 UIResponder 子类)之间的唯一 View 转换来实现的,在相关时给予 First Responder 状态。

(Menu-、GameLevel- 等)TouchHandler 类只会覆盖 touchesBegan/Moved/EndedcanBecomeFirstResponder这样我就可以拦截触摸事件而不会使单个 Controller 和 View 膨胀。我的其他对象都不是 UIResponder。我还没有完全测试过这部分。

对于每个应用程序状态,将创建该状态所需的对象,例如相应的 Scene、TouchHandler、(在 GameLevelState 中具有游戏级别逻辑的 GameLevelModel)等,并在进入下一个状态时释放。

我目前的问题是,当使用 SKTransition 在单个 SCNView 上的多个 SCNScene 之间转换时,在 5-20 次转换后会出现内存泄漏。我尝试通过简化场景、在解除分配之前删除所有 Action 、节点来解决,但没有任何帮助。避免泄漏的唯一方法是避免 SKTransition 并直接将场景分配给 View 的场景属性 scnView.scene = scnScene .所以这将需要我为自己的过渡设置动画。
                         --------------------------
                         |   GameViewController   |
                         --------------------------
                           |  |   |             |
     ------------------    |  |   |             |      ------------------
     | GameLevelsData |-----  |   |             -------|     SCNView    |
     ------------------       |   |                    ------------------
     ------------------       |   |                            |
     |   PlayerData   |--------   |                            |
     ------------------           |                            |
                                  |                            |
                       ----------------                        |
                       | StateMachine |                        |
                       ----------------                        |
                         |                            ------------------
                         |-(*MenuState)---------      |  MenuSCNScene  |
                         |-(LevelState)     |  |      ------------------
                         |-(ConfigState)    |  |
                                            |  |
                     --------------------   |  |
                     | MenuTouchHandler |---|  |
                     --------------------      |
                      -----------------        |
                      |   MenuData    |---------
                      -----------------

              (When entering, each state creates objects of corresponding
              dedicated subclasses for its Model, TouchHandler and Scene)
                                            |  |              |
                    --------------------    |  |     -------------------
                    | LevelTouchHandler |---|  |     |  LevelSCNScene  |
                    --------------------       |     -------------------
                     ------------------        |
                     | GameLevelModel |---------
                     ------------------

提前致谢。

最佳答案

我将根据 Apple 为 SceneKit 提供的示例代码的设计来解释我实际正在从事的真实游戏设计。

正如@HalMuelller 正确指出的那样,您需要将游戏逻辑提取到独立于平台的层中,即使您正在为一个平台编写游戏,这也是一个好主意,因为这将有助于您进行测试。

enter image description here

正如您在上面的类图中所见:

右侧是从 Game 开始的整个游戏逻辑。实际上作为场景和物理代理工作的类。这只是一个普通的旧 ObjC 或 Swift 类。
Game 的主要职责之一类是搭建场景SCNScene来自 SceneKit/Model IO 支持的文件或根据您的情况以编程方式。
Game类也指其他Model类如 Animation加载 3D 骨骼动画和 Player包含球员数据的类,例如他的统计数据,Player在这里指的是一些像棒球运动员一样的球员在比赛中。

还可以看到有PlayerEntityBatterComponent 组成的类,这是基于 GamePlayKit 中的实体组件设计.现在BatterComponent有一个 StateMachine它处理击球手在各种状态之间的转换。

另一个重要组成部分是 BatterControlComponent只有在用户击球时才添加到实体中。这也是一个依赖于平台的组件,因此您可以在 macOS/iOS 目标中独立编写它。同样,连击控制组件由状态机支持,因为状态机也可用于处理控制转换。此控件实现为 SpriteKit场景作为 SCNScene 顶部的叠加层.

如果您正在投球,那么您可以使用 PitcherComponent 配置玩家实体。由另一个状态机支持,依此类推。

在类图的左侧,您可以看到 GameViewController它设置了 SCNView并实例化一个 Game对象和此游戏对象的场景是您的游戏 View Controller 场景 View 呈现的内容。您还确保将场景 View 委托(delegate)设置为游戏对象。

您必须认真引用 Apple 的 SceneKit 示例代码和 GameKit 的示例。在 Apple 开发人员中,示例代码部分搜索:SceneKitGameplayKit .

总的来说,您必须使用普通的旧 Swift/ObjC 类和来自 GamePlayKit 的适当模式来设计一个独立于平台的游戏逻辑层。根据您的游戏要求。

关于生产使用的说明。见 this memory leak issueanimation issues ,所以我不确定 SceneKit 是否已经准备好迎接黄金时段,但 Google 是你的 friend 。话虽如此,如果您已经在Apple平台上工作,SceneKit真的很棒编程。我相信 SceneKit 每年都在改进,在接下来的 2 个版本(WWDC 17、18)中,它应该是一个非常适合 Apple 平台的游戏引擎。根据我的经验,这些是我的 2 美元,YMMV。

关于architecture - SceneKit 游戏架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43081988/

相关文章:

spring - CQ5 Spring 集成

c# - 分层架构中的异常处理

c++ - 禁用 Steam 覆盖

.net - 在 .NET 应用程序中使用 Unreal 3 引擎

ios - 在 scenekit 中的 obj 模型上应用适当的完成?

ios - 需要帮助说明有关法向矢量SceneKit

c# - 如何在 C# 中实现正则表达式单例的常见行为?

api - 当您可以实现版本控制时,为什么开发人员对发布 API 如此珍贵?

swift - 如何更改游戏中的键盘重复率?

ios - SCNNode在 anchor 坐标系内旋转