One of my eureka moment when I learned Unity3D was when Brett Bibby introduced the concept of Single Scene Architecture at one of his talks. As the name said, it means that you only worked with one scene at your release builds. By optimizing into only one scene, we can handle resource loading better and faster. Asynchronous loading, less overhead, and less memory needed.
Disclaimer: All of the development examples comes from Tinker Games’ INheritage BoE. I only speaks from my experience and I’m sure there are better ways, so take this (hell, all of the information in this blog) with a grain of salts again. Yes, I can’t create a reusable tutorial/framework yet.
When I’m developing a game on Unity3D, usually I will create and design scenes according to the flow and functionality I want to achieve. For example: SplashScene, StartScene, StageSelectScene, GameScene, and HighScoreScene to name a few. I will then create a script using Application.LoadLevel() to navigate through them.
On the opposite, on a single scene world, we will only work with one scene (I usually name my scene MainScene) and one object at that scene hierarchy, which is the MainCamera. There are no other objects at first, because it will be created from resource files (XML, json, prefab, what have you) later when needed. Of course, because we’re not using Unity3D scene management, we have to handle that ourselves.
By that, we have to mind (minimum) three things when implementing a single scene architecture. How we serialize and deserialize our object, how we manage our scenes, and how we manage our projects.
The concept of single scene architecture is to minimize all the object at the application starting point and to load all resources on the fly only when needed.
Serialization itself is quite a simple topics. It’s how we save an information or an object into a physical resource file and how to load that back to the original. For example, simple cases of serialization are saving progress data and loading level data.
We want to minimize the objects down to one, so we have to serialize all of other objects. In INheritage, we basically have two kinds of scenes, Menu and Game. Menu scene is where the buttons and images and scrolls take actions whereas Game scene is where the magic happens. The key thing to notice is, all of the Unity3D scene besides Game scene are Menu scenes. And so, we can treat them all the same in serialization-wise!
MenuScene design example in Unity3D.
I began by creating a model from all the elements in the menu. What kind of information needed to make the menu? Sprite, text, actions, glows, etc? I then create a class to hold all of the information and that class can serialize all of the scene data to/from a XML file. That class is also can create game objects according it’s data.
To sum up, I will have a MenuData class (singleton for easy access):
- Holds all menu data information in arrays.
- Initialize() and Clear() for basic data handling.
- Save() and Load() for serialization.
- CreateMenu() for creating game objects.
For serializing, I will have another game object that will save all current scene menu data to MenuData class and use that to save to the XML file. Deserializing just takes a method to load that XML file and another to generate the game objects.
The usual flow for my menu serialization is:
- Design the menu as usual in Unity3D.
- Serialize: Save all menu game objects to MenuData class (using script) and save that to XML.
- Deserialize: Call MenuData.Load() to the XML file and MenuData.CreateMenu() from an empty scene.
The example is for menu, but the basic is all the same for Game scene and whatever specific scene/object you need to serialize.
So we can serialize all of the game objects in one scene, how can we make the transition and interact with each other? We handle this the usual non-Unity3D way: SceneManager / ScreenManager / StateManager. There are a lot of excellent tutorials about managing scene states, so please check others out and implement how you think it best.
For me, I start by creating how a scene is supposed to behave in it’s life. It will have the default behavior to be implemented when awaked, enabled, and destroyed. Load the XML and other resources in Awake(), start the menu transition in OnEnable(), and delete the resources in OnDestroy(). This SceneController script was created as a template and will be used to implement the scenes.
In my menu design, the interaction/transition was implemented on one script per scene. This script will handle how the object transitioning between scenes (which object fade in/out, when to glow, etc.), implement the buttons delegates (what to do when this button is pressed), and other things. All of this functionality will also be copied and used in the SceneController class.
SceneManager is the usual singleton manager that manages the scene transition. My implementation is simple and only changed a little from the initial Brett’s version. Here is the basic flow:
- When we need to change scene, we call SwitchScene in code. For example: SceneManager.SwitchScene(Scene.AboutScene).
- It will then search AboutSceneController script and attach it to the main camera, but NOT enabled yet. it will then load the scene resources.
- When the loading is finished, it will enable the current scene script (AboutSceneController). The game then will transition to that loaded new scene. Also, it will destroy the previous SceneController script that is attached before.
SceneManager in action.
Because the minimal nature of single scene architecture, it will be difficult to debug or changing something. The straightforward solution is use two projects, one (or more) for designing the game and one other single scene project for building the release version.
Unity3D have a great editor capabilities, and it’s on the developer hands to extend the functionalities. Development projects is where you want to go crazy implementing editor that is easy to use and a scene that is polished and usable. Serialize that into XML and use that XML in the single scene project for best use of both worlds.
Using single scene architecture on Unity3D release project will optimize your game more. In your workflow, you will have a minimum of two projects, one design and one build.
- Your design project is the usual development project. All of your scenes objects should be serialized into each own XML or whatever format you prefer.
- Your build project will consist of a single scene, with a MainCamera object and a SceneManager script attached. Maybe others too, but it should be minimal. This SceneManager will handle all of the scene management and attach the corresponding SceneController script according the current scene.
- This SceneController will then load the XML and use that to create the scene objects. It will also manages it scene interaction and transition according to the implementation in the design project by copying it partially and manually.