In this blog post, I’ll present an alternative method to the all-powerful single scene. Techniques such as synchronous and asynchronous scene loading, transition effects, and additive scenes are all possible with Unity’s SceneManager. Surprisingly, complex scene management scripts are not required for implementing any of this functionality. Additive scenes are also very adaptive and can be used to load multiple game scenes, configuration scenes, debugging scenes, and many other useful alternatives.
I originally investigated scene management in Unity to see how well it would handle loading of scenes in real-time, as the player explored the game world. After some experimentation, we’re now using a SceneLoader script in all our game jams, as well as our main title and we’ve been very happy with the results. I hope this post gives you a useful introduction to the scene manager and how to use its most basic functionalities.
I’ve created a GitHub repository of all of the examples, so feel free to skip to the end and download the demo project. Here’s a poor-quality GIF of a prototype I created (with art by Alisha) while working on my first scene loading implementation:
Here at Myriad Games Studio, we do a lot of game jams. Probably every 2 months we’ll do a jam, either an internal one with Myriad, or an organised event such as the TasJam events (run by the folks at the Tasmanian Game Development Society). The internal jams are generally focused on making a game that implements some functionality we want to learn more about. The TasJam events are where we flex our design muscles and try to make an interesting game within specific constraints.
Games jams really help us to see in what areas we need to gain more knowledge. One of the key areas for me was how to setup a game’s scenes and load those scenes smoothly. After discussing with the team, I set aside a couple of weeks to research and implement a scene loading solution. The resulting scripts are simple and easy to add to any new game we make. Every game jam now has a ton of saved time as we have a flexible scene setup and a pre-made scene loading solution. This means we can spend more time in the design phase – the hardest part of game development!
Some of the other more concrete benefits of using the SceneManager, and splitting your game into multiple scenes:
– loading times and memory use are reduced.
– team members can work on separate scenes, therefore reducing the number of source control conflicts.
– truly HUGE open-world games are possible.
– scene transitions and loading screens are super simple to create and add.
– easily add “manager” type scripts and objects to your game.
Here I’ll describe a simple application of Unity’s SceneManager class with a menu scene, a loading screen, and a game scene. In the future, I’ll go through a more advanced version which includes asynchronous scene transitions.
To achieve a working prototype using the scene manager, we need to do the following:
- 1. Setup the scenes and add them to the build settings.
- 2. Add Singleton script to project and create a new script called “SceneLoader.cs”.
- 3. Add scripts as needed to load new scenes using SceneLoader. Could be done using the GUI buttons, in-game scenes, or anywhere really.
This will result in scenes that can be loaded in any order, with simple and easy calls to the SceneLoader class to load a scene or scenes.
The setup of the scenes is very simple. We need 3 scenes with a similar format to the following;
- – Menu scene, containing; Camera, UI button(s).
- – Loading screen scene, containing; Camera, UI (background) image, Animated sprites/loading bar.
- – Game scene(s), containing; Camera, Playable character, UI button (for going back to Menu scene).
Note: you can drag and drop your scenes into the scene hierarchy, and display multiple scenes at once! This is what I’ve done here – super useful for testing.
In older versions of Unity, any scene management was done using the Application class, which contains a hodgepodge of generic static methods. Thankfully Unity has solidified the Scene-related methods into their own namespace – UnityEngine.SceneManagement. This namespace contains most of the useful methods for loading and unloading scenes.
Note: all scene-related methods in the Application class are now deprecated.
The SceneManager contains methods for loading scenes synchronously and asynchronously, so if we go to some extra effort, we can have scenes loading in the background without having the game hang or freeze. So, let’s jump into some code and write our own class called SceneLoader. We’ll start by writing the synchronous versions, to see how they work and how much benefit we can get from implementing the async versions.
I’ve written my SceneLoader class as a singleton, which inherits from MonoBehaviour. This was done for a number of reasons; firstly, singletons lend themselves to manager-type classes, as you generally only want one instance. Secondly, the singleton implementation I use ensures that the game object is never destroyed when a scene is unloaded. Finally, the MonoBehaviour inheritance allows the singleton to have access to inherited methods such as Awake, Start and Update. This also allows you to attach other game objects and scripts to the Manager, if needed.
The singleton implementation is included in the GitHub repo, but can also be found here. It’s a class written by the Unity community (check out some other nice code snippets there too).
This is a super basic implementation but it achieves what we want and we now have a base to build upon. Also, we can access these manager methods (and any public fields) from a script by referencing the singleton Instance, like this: SceneLoader.Instance.DisplayLoadingScene();
Note: make sure you add all the scenes into the build settings.
Calling the LoadScene (line 10) method will load the Loading scene (hmm, should have named that differently) and then load the Game scene. The reason a Coroutine is used in this case, is to allow a simple time-out to be added. Without this, the Game scene would be loaded and displayed before the player has a chance to properly see the Loading scene. Unity loads small scenes very, very quickly!
You can probably spot another problem with this code. We have no way of tracking the loading of our scenes, (well at least, not without going to a lot of trouble to create some kind of loading tracker/subscriber system). There is no way to know when the game scene is actually ready. If it’s not ready then loading it will likely freeze our loading screen. Synchronous methods will lock up the main thread – i.e. everything will stop responding until the scene has finished loading! If you have an animated loading screen, this is a big problem (but should be fine for displaying a static image).
The fix? We move to asynchronous methods of course. This will make our code more complex, but it certainly pays off in the long run.
Going through the class from top to bottom, we have a Property called LoadingProgress (line 9). As you can imagine, this is what we’ll use to track the progress of the game scene as it’s being loaded. Note that it only has a Getter value, which means you cannot accidentally modify it from another script. E.g. SceneLoader.Instance.LoadingProgress = 1f; This is a bit of extra encapsulation built-in to the Property, and a very nice C# feature. Setting of this variable can only happen inside the SceneLoader class, by changing the private variable.
The LoadScene method is designed to be called from whichever script starts the scene loading. It’s not a Coroutine itself, so that our method calls from other scripts are a lot cleaner.
The next method we have written is LoadScenesInOrder (line 17) which is a Coroutine containing a Couroutine! Don’t be put off by nested Coroutines, they actually work amazing well with the SceneManager. LoadSceneAsync returns an AsyncOperation, which inherits from YieldInstruction – the very same inheritance as Coroutine.
This method of listing a sequence of Coroutines or AsyncOperations is a simple and effective technique for loading scenes in order. Loading scenes in this way won’t block the main thread, and will not require explicit tracking, starting or stopping. In the next blog post, more async operations will be added to this method, which will give you an idea of how useful this chaining can be.
The final part of this class is the LoadScene coroutine (line 27) which loads the actual game scene. This method adds more configuration, as we track the loading progress and update our LoadingProgress float. On line 32, we stop the scene from activating when it has finished loading, until we’re ready to activate it. The while loop after this keeps the LoadingProgress float updated, and will wait a frame if the scene has not completed loading.
An important point in the LoadScene method is the check on line 40. Unity presumably only tracks the parts of the scene that can be loaded asynchronously – the final 10% is never reached! Unity documentation itself advises checking for the 90% limit as a way of indicating “loading complete”.
That’s it folks!
This should be a good starting point for implementing your own Scene management class. If you’re not sure how to use the singleton Instance, feel free to check out the GitHub repository linked below. We have not yet covered scene transitions, which will be explored in a future blog post. If you’re keen to see some sample code for that, hit me up on Twitter (@_Walt3r) and let me know!
GitHub project: http://github.com/MyriadGamesStudio/unity-examples
Alan Zucconi tutorials: http://www.alanzucconi.com/2016/03/23/scene-management-unity-5/
Unity tutorials: https://unity3d.college/2016/09/26/scenemanager/