This code loads a first empty Arena scene and then additively features to the level from another scene. It works except that the contents of the second scene pop in ages after the Arena scene is swapped to.
levelToLoad = "arena 0";
StartCoroutine(LoadLevel());
IEnumerator LoadLevel(){
// asynchronously loads the first arena, then the features of that level
AsyncOperation op = SceneManager.LoadSceneAsync("arena",LoadSceneMode.Single);
op.allowSceneActivation = false;
while (op.progress < 0.9f) {
// Report progress etc.
yield return null;
}
StartCoroutine(LoadFeatures());
op.allowSceneActivation = true;
}
IEnumerator LoadFeatures(){
AsyncOperation op = SceneManager.LoadSceneAsync(levelToLoad,LoadSceneMode.Additive);
op.allowSceneActivation = true;
while (!op.isDone) {
yield return null;
}
}
How do you go about loading a multi-scene level so it’s only swapped to when all good and ready?
Can’t be totally certain but looks like … maybe when your LoadFeatures finishes, you could set the first scene to allow activation at that point. (Hold off until then)?
Good catch. I should be waiting on LoadFeatures() completing.
IEnumerator LoadLevel(){
// asynchronously loads the first arena, then the features of that level
AsyncOperation op = SceneManager.LoadSceneAsync("arena",LoadSceneMode.Single);
op.allowSceneActivation = false;
while (op.progress < 0.9f) {
// Report progress etc.
yield return null;
}
yield return StartCoroutine(LoadFeatures());
op.allowSceneActivation = true;
}
Sadly that’s not enough. If I load both additively, they load as expected and then run on top of the introduction. However, if I load the Arena as a single, the additive loading of the features never progresses.
If I use this and don’t async-load Features:
IEnumerator LoadLevel(){
// asynchronously loads the first arena, then the features of that level
AsyncOperation op = SceneManager.LoadSceneAsync("arena",LoadSceneMode.Single);
op.allowSceneActivation = false;
while (op.progress < 0.9f) {
yield return null;
}
SceneManager.LoadScene(levelToLoad,LoadSceneMode.Additive);
op.allowSceneActivation = true;
}
I get exactly the behaviour I want, except the features aren’t asynchronously loaded. Probably fine for what I’m doing as the game is simple, but surely there’s a proper way to do this?!
Sorry, I’m not that familiar with those things, but I agree that it sounds like there should be a way.
I’m glad you got it ‘mostly’ working for your needs for now, at least
I see no reason why the following wouldn’t work.
I added comments for clarification. I haven’t tested this, but my experience tells me this should work.
IEnumerator LoadLevel() {
// asynchronously loads the first arena, then the features of that
AsyncOperation op = SceneManager.LoadSceneAsync("arena", LoadSceneMode.Single);
op.allowSceneActivation = false;
while (op.progress < 0.9f)
{
// Report progress etc.
yield return null;
}
// The line below will wait for the features scene to be loaded.
// No need for coroutines, just use the AsyncOperation.
// Optionally, move the 2 lines below to above the previous while loop (if there is no need to wait for the first level to be almost fully loaded before starting the second asynchronous load).
AsyncOperation featuresOp = SceneManager.LoadSceneAsync(levelToLoad, LoadSceneMode.Additive);
featuresOp.allowSceneActivation = false;
// First wait for the first scene to be fully loaded by yielding for the first AsyncOperation.
yield return op;
// Then wait for the features to be loaded.
yield return featuresOp;
// Now activate them in order.
op.allowSceneActivation = true;
featuresOp.allowSceneActivation = true;
}
“yield return op” never completes, I’m guessing because loading isn’t counted as completed until the scene is activated as ‘loading’ requires all the object initialisation?
You also can’t test for an additional load to be complete as it always counts as incomplete until the parent scene is active.
The more I investigate, the more is seems asynchronous loading this way isn’t possible.
Odd. I worked on a game before which had a loading system exactly like this. I believe in versions of Unity before 5.6 there was also a bug where scenes were not considered fully loaded even though they were (a flag set to false when it should not be). Perhaps as a last resort you could try upgrading, if it’s an option for you.
You have to wait until after your main scene is activated before activating the additively loaded scenes. So you would do
featuresOp.allowSceneActivation = true;
from
void SceneLoaded(UnityEngine.SceneManagement.Scene s, UnityEngine.SceneManagement.LoadSceneMode m) {
}
in some script in your main scene. The reason being that additive scenes will load into the currently active scene. When you call
op.allowSceneActivation = true;
that does two things. It activates the “op” scene and unloads the currently active scene (could be at the end of the current frame or at the next frame). So you have to wait until your new scene is active (when the SceneLoaded delegate is fired) before you activate your additive scenes.
Is that any different than what I was doing? I enabled the features before the level scene, but they weren’t activated until after the level scene was swapped to, causing the pop-in.