Search Unity

Question How to wait for all additive scenes before executing logic?

Discussion in 'Scripting' started by Mauschelbaer, Jan 8, 2023.

  1. Mauschelbaer

    Mauschelbaer

    Joined:
    Aug 4, 2019
    Posts:
    17
    In my game I have a Scene called "Loading". In it I load two scenes that make up the in-game screen: "Gameplay" and (e.g.) "TestMap01".

    Screenshot 2023-01-08 184406.png

    This is the code from my Loading-Scene which will load the in Game so it looks like in the screenshot:
    Code (CSharp):
    1.  
    2. public class LoadingMenu : MonoBehaviour
    3. {
    4.     public void Start()
    5.     {
    6.         scenesToLoad.Add(SceneManager.LoadSceneAsync("Gameplay"));
    7.         scenesToLoad.Add(SceneManager.LoadSceneAsync("TestMap01", LoadSceneMode.Additive));
    8.         StartCoroutine(LoadingScreen());
    9.     }
    10.  
    11.     IEnumerator LoadingScreen()
    12.     {
    13.         float totalProgress = 0;
    14.         for (int i = 0; i < scenesToLoad.Count; ++i)
    15.         {
    16.             while (!scenesToLoad[i].isDone)
    17.             {
    18.                 totalProgress += scenesToLoad[i].progress;
    19.                 loadingProgressBar.fillAmount = totalProgress / scenesToLoad.Count;
    20.                 yield return null;
    21.             }
    22.         }
    23.     }
    24. }
    25.  
    However, I often have the problem that many Start() or Awake() methods from scripts are executed before the map (i.e. the second additive loaded Scene) has been loaded, so that a lot of the logic simply doesn't work (e.g.
    GameObject .Find(...)
    can't find anything yet because it doesn't exist yet).

    My question: How can or should I ensure that everything was finally loaded?
     
  2. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    Your LoadingScreen function looks fine -- it won't finish until all scenes have loaded. The problem is that Awake() and Start() don't interact with it. Of course the ones in the first scene run immediately, possibly before the other scene is loaded. Why wouldn't they?

    The fix I use is another start-like function in the "game manager" (the main script) for whatever got loaded -- call it start2 or runMeAfterAllIsLoaded or something. When LoadingScreen is completely done, have it find the main script in the new scene, and run the second Start (or have it set an "allLoadingDone" bool to tell someone else to do it).
     
  3. Mauschelbaer

    Mauschelbaer

    Joined:
    Aug 4, 2019
    Posts:
    17
    That sounds great! Before I go into that, another problem:

    The strange thing is that I can't execute any logic outside of the while loop.
    Could it be because the "LoadingScene" is unloaded as soon as the first scene ("Gameplay"; NO additive) has finished loading and therefore the coroutine (which is in the script in the LoadingScene) is simply aborted/unloaded?


    Code (CSharp):
    1.  
    2.     IEnumerator LoadingScreen()
    3.     {
    4.         float totalProgress = 0;
    5.         for (int i = 0; i < scenesToLoad.Count; ++i)
    6.         {
    7.             while (!scenesToLoad[i].isDone)
    8.             {
    9.                 totalProgress += scenesToLoad[i].progress;
    10.                 loadingProgressBar.fillAmount = totalProgress / scenesToLoad.Count;
    11.                 Debug.Log("...") //<------- OK
    12.                 yield return null;
    13.             }
    14.                 Debug.Log("...") //<------- not printed!
    15.         }
    16.                 Debug.Log("...") //<------- not printed!
    17.     }
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,934
    Most likely. Coroutines are attached to the monobehaviours that started them. Once that scene is unloaded the coroutine will cease to run.

    You may need to do a step by step additive load, then have this initial scene unload itself (or have the loading scene unload it).