- Home /
Is it possible to use LoadSceneAsync to load multiple scenes and wait for all of them to be ready?
I am attempting to move from the old setup (pre Unity 5.3) where there was always a single scene to embrace the new way of things where multiple scenes can be loaded additively. This seems like it's going to be useful for us from a development process standpoint so that different people can work on different parts of the scene without having to worry about future merging of files.
What this means, however, is that my nice friendly LoadSceneAsync() call that was working before is no longer going to work in quite the same way and I'm becoming convinced it might not be possible to actually load scenes in the sequence we need them to load. Specifically, I'd like to be able to load all 5 parts of my scene fully in the background, while my loading screen is still animating away, and then once they're all ready, activate them all so their objects' Awake() methods all get called in the same frame. This way the sequencing is as similar as possible to the way it used to work and allows things that automatically form links with other elements of the world to continue to do their thing appropriately.
Here's a simplified version of what I attempted that seemed closest to working as I wanted:
private IEnumerator LoadSequence () {
// Kick off the loading but don't do the activation of any of these scenes yet.
AsyncOperation firstOp = LoadSceneAsync("SceneA", LoadSceneMode.Single);
firstOp.allowSceneActivation = false;
AsyncOperation secondOp = LoadSceneAsync("SceneB", LoadSceneMode.Additive);
secondOp.allowSceneActivation = false;
// Wait until everyone is ready for activation - Unity uses 0.9f as a magic number denoting ready-for-activation.
// BROKEN: This is where things fail - secondOp.progress never goes beyond 0.
// It seems that it can't start its loading until firstOp has been activated.
while (firstOp.progress < 0.9f || secondOp.progress < 0.9f) {
yield return new WaitForSecondsRealtime(0.1f);
}
// Everyone's loaded, let's let everyone activate.
firstOp.allowSceneActivation = true;
secondOp.allowSceneActivation = true;
// May not be necessary?
yield return null;
}
Unfortunately, what happens here is that secondOp's progress stays 0 forever. Apparently, since firstOp is never allowed to finish its activation the secondOp isn't ever allowed to load.
Is there some totally other way I'm not seeing to do all the loading THEN all the activation (Awake() calls) at the same time/in the same frame? Is there something I'm misunderstanding about Asynchronous scene loading in Unity? Right now I've just fallen back to synchronous loading which makes things generally work, but now my loading screen is very sad and static since it's sitting there with the main thread blocked.
Answer by Harinezumi · May 29, 2017 at 09:42 AM
Hi there!
Sorry if I'm necroing this thread, but as there is no answer yet, I think my findings may help. I use Unity 5.6.0p4.
I was trying to do the same as Michael-Thomas, load 2 scenes, one in single and the other additive mode. I tried various ways, doing them in "paralel" as above, waiting for one to reach 0.9 progress then starting the other, and even activating one before loading the other. In the first 2 cases the operations never complete, and in the second case the second scene never loads.
Then I tried loading both additively, and it worked! So it seems that you cannot mix single and additive scene loading and have allowSceneActivation false (for either of them). Of course, this way the original scene will remain, so you need to deactivate its camera and EventSystem before you activate the scene that has that. I did the loading the following way:
private IEnumerator LoadScenesAsync (List<string> namesOfScenesToLoad) {
Scene originalScene = SceneManager.GetActiveScene();
List<AsyncOperation> sceneLoads = new List<AsyncOperation>();
for (int i = 0; i < namesOfScenesToLoad.Count; ++i) {
AsyncOperation sceneLoading = SceneManager.LoadSceneAsync(namesOfScenesToLoad[i], LoadSceneMode.Additive);
sceneLoading.allowSceneActivation = false;
sceneLoads.Add(sceneLoading);
while (sceneLoads[i].progress < 0.9f) { yield return null; }
}
// TODO: deactivate conflicting components from originalScene here
// need to have at least one active scene before unloading the originalScene
for (int i = 0; i < sceneLoads.Count; ++i) {
sceneLoads[i].allowSceneActivation = true;
while (!sceneLoads[i].isDone) { yield return null; }
}
AsyncOperation sceneUnloading = SceneManager.UnloadSceneAsync(originalScene);
while (!sceneUnloading.isDone) { yield return null; }
}
I hope this helps!
Is it possible to set a scene as active on the moment it is loaded ?
A problem I have with this solution is : Some objects are instantiated on Awake as sceneB is loaded, but they are set up into the loading screen, which I'm trying to remove.
I had a similar problem, one scene starting its logic while the other was still loading. I solved it by creating a scene controller script, that in its Awake()
or Start()
function starts a coroutine, that checks if LoadScenesAsync()
is still in progress, and waits for it to finish (I put LoadScenesAsync()
into a persistent singleton script, that stores the loading coroutine and has an IsLoading()
function). The scene controller starts to initialize and instantiate objects only after scene loading has finished (and it even waits one additional frame).
However, in your case I would create a very light-weight loading scene, load it as a single scene, and start loading the actual scene in it additively. Then just before activating the actual scene, deactivate the loading scene.
The second solution is pretty much what I tried to do, but unfortunately Unity refuses to unload the loading screen just yet because it is the only remaining loaded scene.
For now I figured how to instantiate objects in a specific scene. We can't set the scene directly, but we can still tinker with the object's transform :
var goo = new GameObject ("goo");
Debug.Log (goo.scene.name);
goo.transform.parent = this.transform; // any transform in the target scene.
goo.transform.parent = null;
Debug.Log (goo.scene.name);
Thanks! Saved my head) I'll put in my two cents: I had a problem with my current loaded scene, objects are still loded into memory, even I unload it via UnloadSceneAsync() (especially issue was on freshly loaded scenes and objects which try to fetch $$anonymous$$ainCamera). If you had issue like this, loop over all root gameobjects in current scene (scene.GetRootGameObjects();) and turn them all down. Edit: I use Scene$$anonymous$$anager.CreateScene() to create dummy scene, set it as active scene and then turn down objects and unloading current scene. Without this magic current scene is never unloaded.
Your answer
Follow this Question
Related Questions
Particular scene loads fine in the Unity Editor, but unable to load in the executable? 0 Answers
How to make Awake and Start get called in order with additive scenes? 1 Answer
How to load scene without unloading previous scene ? 0 Answers
buttons not being able to be clicked? 1 Answer
How Do i Get Rid Of A Scene Without Deleting It's Objects 1 Answer