Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Question Is There a way to regret SceneManager.LoadSceneAsync()?

Discussion in 'Scripting' started by Babybus_Study, Aug 20, 2020.

  1. Babybus_Study

    Babybus_Study

    Joined:
    Oct 31, 2016
    Posts:
    14
    Hi,
    I try to optimize the scene loading speed by pre loading the next scene(Scene1), and set the
    asyncOperation.allowSceneActivation = false
    , until the actual scene change happened. But player has a change will go to other scene(Scene2) instead of pre loaded Scene1.

    Here's the problem:

    If the player choose to go Scene2, then Scene1 will become active first for a split second and then go to Scene2. even the scripts in Scene1 runs their Awake functions.

    I tried to Unload Scene1 before going to Scene2, but problem still there, I don't know this behavior is intended or a bug?

    Here's my code:

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.SceneManagement;
    4.  
    5. public class TestSceneLoading : MonoBehaviour
    6. {
    7.     private static void OnSceneChange(Scene oldScene, Scene newScene)
    8.     {
    9.         Debug.Log($"oldScene:{oldScene.path}");
    10.         Debug.Log($"newScene:{newScene.path}");
    11.     }
    12.  
    13.     private void Awake()
    14.     {
    15.         SceneManager.activeSceneChanged += OnSceneChange;
    16.     }
    17.  
    18.     private IEnumerator Start()
    19.     {
    20.         Debug.Log("start loading Scene1");
    21.         var ao = SceneManager.LoadSceneAsync("Scene1");
    22.         ao.allowSceneActivation = false;
    23.         while (ao.progress < .9f)
    24.         {
    25.             yield return null;
    26.         }
    27.         Debug.Log("Scene1 loaded");
    28.         yield return new WaitForSeconds(2);
    29.         Debug.Log("prepare to unload Scene1");
    30.  
    31.         ao = SceneManager.UnloadSceneAsync("Scene1",UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);
    32.  
    33.         yield return ao;
    34.        
    35.         Debug.Log("Scene1 unloaded, prepare to go Scene2");
    36.         yield return new WaitForSeconds(2);
    37.        
    38.         Debug.Log("start going to Scene2");
    39.         SceneManager.LoadScene("Scene2");
    40.     }
    41. }
    and result log is:

    Snipaste_2020-08-20_09-49-12.jpg
    Red square shows that Unity went to Scene1 first.
    Orange square shows that Scripts in Scene1 executed their Awake function.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,420
    Interesting edge case. It might be you need to load yet another scene with a canvas in front of it that is fully black and just fake it that way... Sounds like you have understood the timing and I guess it has to Activate the scene before it unloads it.

    Or perhaps you can iterate all the objects in Scene1 and destroy them the same frame they become active? Not sure if that would still result in a flash though... scenes don't really finish loading until end of frame. Perhaps you could do the destroy all objects right in the OnSceneLoaded callback... I imagine that would likely be early enough?
     
  3. Babybus_Study

    Babybus_Study

    Joined:
    Oct 31, 2016
    Posts:
    14
    if I have to do this many things to avoid bad things happen, I would rather not preload Scene1 in the first place.

    Still a interesting case to discuss though
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,420
    I assume "bad things happen" is a one-frame flash of the Scene1 before then Scene2 loads?

    Why not just destroy the camera? And if Scene2 is already loaded, turn its camera off for one frame, then back on.