I am trying to design an architecture for a SceneKit iOS game. I've shown below two rough high level object diagrams/graphs of my current preferred ideas.
I am only looking at the high level architecture at the moment, i.e. managing transition between Menu/GameLevel/Config/Paused app states and making the app data-driven, so that it can handle multiple levels, etc. Once I get this working, then I'll address lower level architecture, e.g. for the GameLevel state I'll have a GameLevelModel object to represent an actual game level logic.
Would be great to hear which one looks more promising, any obvious pitfalls or things to avoid?
I'm trying to stay close to the MVC paradigm with this version.
The behaviour of the app changes significantly between its different states (Menu/GameLevel/Config/etc) so I'll be using a permanent container view controller that will manage/transition between several nested VCs, in a parent-child relationship as per Apple's "View Controller Programming Guide for iOS". These will be effectively entire MVCs.
Because none of Apple's container controllers (UINavigation-, UISplitScreen-, UITabBar-) are suitable (I need the entire screen) I'll have a custom container VC (RootViewController) that will have one nested child VC at all times. The View of each child VC will be fully covering the container's one at all times. The transition between child VCs will be managed by the RootVC and driven by its StateMachine.
Each child VC (effectively entire MVC) is created each time when its corresponding state becomes current and then deallocated when it is replaced with next state's one and no longer needed. Similar to how UINavigationController deals with it's contained VCs.
My only worry with this architecture is that it seems a bit heavy. SceneKit looks like it's designed to work with a single SCNView and to transition between multiple SCNScenes when we need to change the 3D content. This gives more transition options as well.
--------------------------
| 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 |
------------------ ------------------
I'll have only one View Controller (GameViewController) with its View (SCNView) and they will last for the entire app lifecycle. (I will not have container and nested VCs here.)
The change in behaviour and content between app states (Menu/GameLevel/Config/etc) is achieved by the only View transitioning between Scenes and different TouchHandlers (UIResponder subclasses for each state) given First Responder status when relevant.
The (Menu-, GameLevel-, etc) TouchHandler classes will only override touchesBegan/Moved/Ended
and canBecomeFirstResponder
so that I can intercept touch events without bloating the single controller and view. None of my other objects are UIResponders. I've not tested exactly this part yet.
With each app state the required objects for that state will be created, like corresponding Scene, TouchHandler, (GameLevelModel with game level logic when in GameLevelState), etc and deallocated when next state is entered.
My current issue with this one is, that when using SKTransition to transition between multile SCNScenes on the single SCNView, after 5-20 transitions there is memory leakage. I tried resolving by simplifying the scene, removing all actions, nodes before deallocating but nothing helps. The only way to avoid leakage is avoiding SKTransition and directly assigning scenes to the View's scene property scnView.scene = scnScene
. So this will require me to animate my own transitions.
--------------------------
| 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 |---------
------------------
Thanks in advance.
I will explain a real game design that I am actually working on and was based on the design of the sample codes provided by Apple for SceneKit.
As @HalMuelller correctly points out, you need to extract the game logic into a platform independent layer, and that is a good idea even if you are writing the game for one platform as that will help you in testing.
As you can see in the class diagram above:
On the right side is the entire game logic starting with a Game
class which actually works as the scene and physics delegate. This is just a plain old ObjC or Swift class.
One of the main responsibility of the Game
class is to build scenes SCNScene
either from files supported by SceneKit/Model IO or programmatically as your case may be.
The Game
class also refers to other Model
classes such as Animation
which loads 3D skeletal animations and Player
class which contains the player data such as his statistics, the Player
in here refers to some player like a baseball player in the game.
You can also see that there is a PlayerEntity
class which is made up of BatterComponent
, this is based off the Entity-Component design from GamePlayKit
. Now the BatterComponent
has a StateMachine
which handles the batter's transitions between various states.
The other important component is BatterControlComponent
which you add to the entity only when the user is batting. This is also a platform dependent component, so you can write this independently in your macOs/iOS targets. Again the batter control component is backed by a state machine as State machine can also be used for handling controls transitions. This control is implemented as a SpriteKit
scene as an overlay on top of the SCNScene
.
If you are pitching, then you configure the player entity with the PitcherComponent
backed by another state machine and so on.
On the left side of the class diagram, you can see sits a GameViewController
which sets up an SCNView
and also instantiates a Game
object and this game object's scene is what your game view controllers scene view renders. You also ensure that you set the scene view delegate to be the game object.
You must seriously refer to the Apple sample codes for SceneKit and the samples for GameKit. In Apple developer, Sample Code section search for: SceneKit
and GameplayKit
.
Overall you must design a platform independent game logic layer using plain old Swift/ObjC classes and the appropriate patterns from GamePlayKit
based on your game requirements.
A note on production usage. See this memory leak issue and animation issues, so I am not really sure if SceneKit is yet ready for prime time, but Google is your friend. Having said that, SceneKit is really great if you are already working on Apple platform so the turn around time vis a vis learning a new game engine is lesser if you have not used any game engine and are writing games as a hobby or to learn game programming. I believe that SceneKit has been improving every year and in the next 2 releases (WWDC 17, 18) it should be a really polished game engine for Apple platforms. These are my 2$ based on my experience, YMMV.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With