This document is about: QUANTUM 2
SWITCH TO

This page is a work in progress and could be pending updates.

Scene Loading Sample

Level 4

Overview

The scene loading sample is a technical sample that aims to explain how the developer can make their own scene loading for production. Addressable scenes and pre-load a scene before starting the simulation are also showcased.

Scene Loading for Quantum

There are 2 important parts when talking about scene loading with Quantum and these 2 distinct logics needs to communicate with each other.

Simulation Map

The Map contains information about the scene that is used by the deterministic simulation to drive gameplay. The Map can be directly changed from the simulation with frame.Map = {YourMap}, Quantum will unload everything from the previous and load the new one.

You can read more about Map Baking, but the important part here is to notice that this is only for the simulation side. Unity will not respond to that if it is not using the default scene loader provided.

Unity Scene

To provide the correct visuals to the player, it is necessary to react to changes in the Map. This is where the scene loader's greatest responsibility comes in: constantly checking the Map defined by the Frame and, upon detecting changes, loading the corresponding Unity Scene.

Addressable Scene

An Addressable scene should not differ much from the normal scene loading process, but it is needed to have an AssetReference reference of the scenes.

When a Map change is detected, simple check if the scene related is one of the addressables one, return the AssetReference if positive and load it using the Addressables.LoadSceneAsync() function.

C#

// Map change detected

if (CheckAddressableScene(map, out var sceneAssetRef))
{
  // Addressable scene loading.
  yield return LoadAddressableScene(map.Scene, sceneAssetRef);
} else
{
  // Normal scene loading.
  yield return SceneManager.LoadSceneAsync(map.Scene, LoadSceneMode.Additive);
}

C#

/// <summary>
/// Check if a map scene is addressable.
/// </summary>
private bool CheckAddressableScene(Map map, out AssetReference sceneAssetRef)
{
foreach (var addressablesScene in _addressablesScenes)
{
  if (map.SceneGuid == addressablesScene.AssetGUID)
  {
    sceneAssetRef = addressablesScene;
    return true;
  }
}

sceneAssetRef = null;
return false;
}

C#

private IEnumerator LoadAddressableScene(string sceneName, AssetReference sceneAssetRef)
{
var instance = Addressables.LoadSceneAsync(sceneAssetRef, LoadSceneMode.Additive);
yield return instance;
// Storing for unload logic.
_addressablesScenesHandler.Add(sceneName, instance.Result);
}

Load Scene First

The default behaviour is to load the scene after the simulation is started, but it is possible to load the scene beforehand if needed. This sample's approach is based on 3 steps.

  1. Check if the local player is currently on a room and the simulation didn't started yet.
  2. Enable the Start Game button only if all clients have already confirmed that the scene is loaded on their end.
  3. Check if the initial map has changed and load the related scene if needed.

C#

// If the simulation is not started yet and LoadFirst is true, check if all clients already loaded the scene or if there's a change on the selected map.
private void Update()
{
    if (!LoadFirst) return;
    
    // (1)
    var inRoom = UIMain.Client != null && UIMain.Client.InRoom;
    var inGame = QuantumRunner.Default && QuantumRunner.Default.IsRunning;
    if (inGame || inRoom == false) return;
    
    // (2)
    MasterCheckStart();
    
    // (3)
    if (UIMain.Client.CurrentRoom.CustomProperties.TryGetValue("MAP-GUID", out var mapGuid))
    {
      var map = UnityDB.FindAsset<MapAsset>((long)mapGuid).Settings;
      if (_currentMap == map || _busy) return;
    
      // If the map has changed and each client will load it before the simulation starts, set the scene loaded property to false.
      var playerProperties = UIMain.Client.LocalPlayer.CustomProperties;
      playerProperties["SCENE_LOADED"] = false;
      UIMain.Client.LocalPlayer.SetCustomProperties(playerProperties);
    
      LoadScene(map);
    }
}
Back to top