This tutorial shows how the manage scenes and levels in Unity 5.3, with the introduction of UnityEngine.SceneManagement.

Introduction

It took Unity more than 5 versions, but it seems that finally it’s converging towards a uniform and sensible set of APIs to manage scenes. In its initial version, Unity scenes were referred in the code as levels. It came pretty quickly the realisation that scenes do not necessarily define “different” levels; this forced the introduction of the term “scene” directly into the API. From a logical point of view, levels are addressed with their build number (the order in which they are included into the Build Settings); scenes are referred with the name of the asset that contains them. Neither of those, however, are reliable unique identifiers for a scene. Moving scenes in the Build Settings shifts all of their indices. Similarly, you can have two scenes with the same name, stored in two different folders. All of these aspects have fuelled a lot of confusion, which Unity 5.3 is trying to end.

What’s new in Unity 5.3

Unity 5.2 allowed scenes to be referred with either their build index or their asset name. In Unity 5.3 there is an additional way, which is the Scene struct (documentation). It’s a wrapper for common methods and variables such as buildIndex, name and path.

Accessing the SceneManager class

In order to use these features of Unity 5.3, you need to include in your C# files this package SceneManagement:

using UnityEngine.SceneManagement; 1 using UnityEngine . SceneManagement ;

This gives access to the SceneManager class (documentation), which replaces the obsolete functionalities of Application.

Retrieving the current scene

One of the main reasons why Unity changed its naming convention from “level” to “scenes” is mainly because you can load multiple scenes at the same time. This breaks the concept of “current level”, which has been replaced with “active scene”. In the vast majority of cases, the active scene is the last one that has been loaded. You can query it at any given time using GetActiveScene:

// 5.3 Scene scene = SceneManager.GetActiveScene(); Debug.Log(scene.name); Debug.Log(scene.buildIndex); // 5.2 Debug.Log(Application.loadedLevelName); Debug.Log(Application.loadedLevel); 1 2 3 4 5 6 7 8 // 5.3 Scene scene = SceneManager . GetActiveScene ( ) ; Debug . Log ( scene . name ) ; Debug . Log ( scene . buildIndex ) ; // 5.2 Debug . Log ( Application . loadedLevelName ) ; Debug . Log ( Application . loadedLevel ) ;

You can test against a specific scene simply by using:

if (SceneManager.GetActiveScene().name == "sceneName") { // ... } 1 2 3 4 if ( SceneManager . GetActiveScene ( ) . name == "sceneName" ) { // ... }

Alternatively you can use the == operator to compare two scenes:

if (SceneManager.GetActiveScene() == scene) { // ... } 1 2 3 4 if ( SceneManager . GetActiveScene ( ) == scene ) { // ... }

Unity has overridden the behaviour of == so that it works as expected.

Loading a single scene

Like in Unity 5.2, scenes can be loaded using their build index or their name.

// 5.3 SceneManager.LoadScene(4) SceneManager.LoadScene("scene4") SceneManager.LoadScene("path/to/scene/file/scene4") // 5.2 Application.LoadLevel(4); Application.LoadLevel("scene4"); 1 2 3 4 5 6 7 8 // 5.3 SceneManager . LoadScene ( 4 ) SceneManager . LoadScene ( "scene4" ) SceneManager . LoadScene ( "path/to/scene/file/scene4" ) // 5.2 Application . LoadLevel ( 4 ) ; Application . LoadLevel ( "scene4" ) ;

Weirdly, the new LoadScene doesn’t accept Scene structs. When a new scene in loaded with this method, the previous one is unloaded (all its objects destroyed). The game will freeze for a little bit while the new scene is being loaded and activated.

Reloading a scene

There is no single function to reload the current scene. The best way you can do is to get the build index of the current scene, and pass it to LoadScene:

SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); // 5.3 Application.LoadLevel(Application.loadedLevelName); // 5.2 1 2 SceneManager . LoadScene ( SceneManager . GetActiveScene ( ) . buildIndex ) ; // 5.3 Application . LoadLevel ( Application . loadedLevelName ) ; // 5.2

This only works as intended if you have a single active scenes. If you have loaded multiple scenes, this will only reload the last active one.

Issues

Ghost scenes. Every time you load a new level with SceneManager . LoadScene , Unity flushes all the scenes that have been previously loaded. Only game objects that invoked DontDestroyOnLoad (documentation) survive the process. This means that you can potentially use LoadScene , yet having all the previous scenes still loaded. Despite this, Unity will fail to realise that those scenes are actually still alive.

Every time you load a new level with , Unity flushes all the scenes that have been previously loaded. Only game objects that invoked (documentation) survive the process. This means that you can potentially use , yet having all the previous scenes still loaded. Despite this, Unity will fail to realise that those scenes are actually still alive. Scene struct. The Scene struct does not update itself. If something in the scene has changed, its isDirty flag won’t suddenly become true . If you want to query the state of the scene, you should not store the structure; use GetActiveScene instead.

Conclusion

Become a Patron!

This tutorial shows some of the features introduced by Unity 5.3 to manage scenes. All the changes that Unity is making to its engine are bringing closer to a more clean and reliable flow to handle the dynamic loading of content. There are few aspects, however, that are still quite messy. And is unlikely Unity is going to get rid of them any time soon.

The next part of this tutorial will explore how to load scenes asynchronously, implementing a loading bar.

Other resources

Part 1. Scene Management in Unity 5

Part 2. Implementing a Loading Bar in Unity 5

Part 3. Seamless Scene Loading in Unity