- Home /
Loading Level Async without switching the level immediately
Hi,
I was wondering if it was possible to load a level async a head of time, and then at a later point of my choosing switch to that level? Additive loading is not really an option here since our levels are all stand alone islands.
Because when using asyncOperation = Application.LoadLevelAsync(LevelName);
Then it immediately switches level after it is done loading it. Imagine that the player is running down a corridor in game, and we start loading the next level with this function and there is something the player forgot in the level and turns around to go back. But now the loading has ended and it immediately switches level. We would rather have the loading happen in the background and when you reach the end of the corridor we tell the engine to switch level based upon if it is finished loading or not.
Is this possible?
magnificent find, @sean
http://docs.unity3d.com/Documentation/ScriptReference/AsyncOperation-allowSceneActivation.html
thanks for that. it really pays to keep up with new things they've added - thank you again.
Answer by SeanAtr0n · Mar 03, 2013 at 05:28 AM
This is possible now without additive scenes by using async.allowSceneActivation, however it is currently (4.0.1) somewhat dangerous.
Note: Unity will CRASH if you don't let it complete any async load operation that you start. so...
Don't exit play mode while an async load is waiting to be activated.
Don't let players cancel scene transitions once the async load starts
Less important notes:
Your next scene's initialization is probably the real problem, try to optimize init before worrying about async load.
The lag that appears when you first call LoadLevelAsync is only present in the editor.
public string levelName; AsyncOperation async; public void StartLoading() { StartCoroutine("load"); } IEnumerator load() { Debug.LogWarning("ASYNC LOAD STARTED - " + "DO NOT EXIT PLAY MODE UNTIL SCENE LOADS... UNITY WILL CRASH"); async = Application.LoadLevelAsync(levelName); async.allowSceneActivation = false; yield return async; } public void ActivateScene() { async.allowSceneActivation = true; }
Just call StartLoading() when you are certain that a scene transition is incoming and then ActivateScene() when you are ready to swap.
Hopefully we can start figuring out safer ways to do this as more people start using allowSceneActivation. I'm willing to live with the danger of unity crashes to avoid the hassle of additive scene loading.
I've been trying this, but all I can seem to do is crash the editor. If I put code after the yield it just doesn't execute - both with and without allowSceneActivation. Setting allowSceneActivation to false just freezes the editor.
private AsyncOperation async;
private void Start()
{
StartCoroutine(LoadScene());
}
IEnumerator LoadScene()
{
if (sceneName == "")
yield break;
async = Application.LoadLevelAsync(sceneName);
async.allowSceneActivation = false;
Debug.Log("start loading");
yield return async;
}
private void SwitchScene()
{
Debug.Log("switching");
if (async != null)
async.allowSceneActivation = true;
}
private bool fading = false;
private void Update()
{
if (async != null && async.isDone)
{
if (!fading)
{
Debug.Log("done loading");
fading = true;
CameraFade.CreateOneOff(Color.clear, Color.black, 2.0f, SwitchScene);
}
}
}
Guess async.isDone might not trigger until you let the load finish.
I know async.progress updates, You might have better luck if you start the fade at something like (async.progress > 0.9)
Wow, that's actually good to know that they implemented this finally. However it's not so good to hear that it's buggy from the first day... Hopefully they fix it. Loading asynchronous without the control when to switch was quite useless.
that is literally the first time I have known something before @Bunny ! :) Hooray! :) Only by 15 days but still :)
You know I fear )apart from the bug) Unity is still no good at strea$$anonymous$$g in any large files (other than audio) http://answers.unity3d.com/questions/433609/hiccups-when-loading-images-from-resources-folder.html
I've found that the yield return async; call won't return until you set the async.allowSceneActivation=true somewhere else, until that happens, the async.progress sits at .9f
Answer by DavidDebnar · Jun 29, 2011 at 12:14 PM
No, I dont think its currently possible, LoadLevelAsync is mostly for showing a loading screen or something like that...but if you want a smooth load, than you could make a gui lerp, that lerps the screen to black, than loads the level, and in the next scene lerps it back... the only way to to what you want is to use Application.LoadLevelAdditiveAsync, and than destroy the objects from previous scene...but its really complicated.
If you wanna use the lerp/fade then check Fade. I really like the extension and I use it for fading into videos, or through levels :).
My script for fading into movies. //use this link if the first one isn't working
David
Please don't use tinypaste.com for posting scripts. The site requires me to participate in some sleazy ad revenue crap in order to view the page. Please post it on the UnityWiki like the Fade script or use a reputable site like pastebin.com. I dived into the page source before they could block my mouse input and put it up on pastebin here: http://pastebin.com/d2Dwx3Yc
Still a nice addon script to accompany the fade script.
Answer by MetaMythril · May 31, 2012 at 07:22 PM
You would definitely have to use something like Application.LoadLevelAdditiveAsync.
It's not too terribly difficult if you structure your sub scenes well. My method is to pack an entire sub scenes contents under one GameObject. Then when I load a level using AdditiveAsync, I place that content under a root content GameObject in my base scene. Then when I want to destroy my old scene data I just destroy the content object and recreate it using new scene objects.
It would look something like this: BaseScene
--GameManagerGameObject
--ContentRootGameObject
MyNewScene
--MyNewSceneRootGameObject
----MyNewSceneSubGameObjects
A loaded scene would look like this if you loaded MyNewScene additively: BaseScene
--GameManagerGameObject
--ContentRootGameObject
----MyNewSceneRootGameObject
------MyNewSceneSubGameObjects
Then you just destroy ContentRootGameObject from your GameManagerObject, release unused assets, then repeat for each new level.
Here is the loading code I'm using currently:
private IEnumerator LoadLevel()
{
if (string.IsNullOrEmpty(_levelToLoad)) yield return 0; // Nothing to load!
Debug.Log("ManagerGame: Level[" + _levelToLoad + "] loading level");
var go = GameObject.Find("ContentRoot");
if (go != null)
{
DestroyImmediate(go);
Resources.UnloadUnusedAssets();
}
AsyncOperation async = Application.LoadLevelAdditiveAsync(_levelToLoad);
yield return async;
go = new GameObject("ContentRoot");
GameObject.Find(_levelToLoad).transform.parent = go.transform;
Debug.Log("ManagerGame: Level[" + _levelToLoad + "] loading complete");
}
When I do this I get a flash of the scene. Did you guys do something to get around that?
If you are transitioning between two scenes, the easy way is to throw up a black UI screen before you destroy and load new assets. The more complex way is for you to hit an invisible trigger along the way that causes loading of new material to occur in the background via the async operation while the contents are still not within rendering distance and when you hit another trigger, unload the old material that should be out of sight.
Hey guys, I'm also implementing something very similar to your solutions but when the new scene is being loaded in background, the game lags and its quite obvious for the user. Is there are way to hide this lag?
@bardhlohaj If you are loading without the aid of a UI screen to hide the loading, the only thing I can think of is that you have to stretch out whatever you are loading so that not too many items are being loaded at once. I haven't done loading while still moving about a scene, so I can't see exactly the nature of the issue. I would hope that Unity's method would do "metering out loading as to not adversely impact the current scene" for you but it seems that might not be the case.
You may have to come up with your own controlled method of loading objects. Loading and unloading things from memory are the one of the biggest ways for a game to experience hiccups.
Answer by wladivinci · Jan 15, 2020 at 02:02 AM
Hello, this is quite old, but useful for me now. I use it with SceneManager.LoadSceneAsync() because the other is obsolete. Also I think it's not necessary to run it in a Coroutine, because it already is one. Also it's not buggy anymore.
Your response is not an answer. You need to create a new question so people can properly respond to your problem.
Thanks! I edited it. $$anonymous$$y question is now here: https://answers.unity.com/questions/1691388/loading-muiltiple-scenes-async.html
Answer by pantoygames · Nov 19, 2020 at 12:47 PM
Here is my code... i can wait 1 second before and after
private void Start()
{
StartCoroutine(LoadSceneAsync("GameScene"));
}
IEnumerator LoadSceneAsync(string sceneName)
{
yield return new WaitForSeconds(1);
var asyncLoad = SceneManager.LoadSceneAsync(sceneName);
asyncLoad.allowSceneActivation = false;
var hasWaitLoad = true;
while (!asyncLoad.isDone)
{
if (asyncLoad.progress == 0.9f)
{
if (hasWaitLoad)
{
hasWaitLoad = false;
yield return WaitLoad(asyncLoad);
}
}
yield return null;
}
}
IEnumerator WaitLoad(AsyncOperation asyncLoad)
{
yield return new WaitForSeconds(1);
asyncLoad.allowSceneActivation = true;
}
Your answer
Follow this Question
Related Questions
Why does Application.LoadLevelAsync cause a huge spike? 2 Answers
getting loading progress for a level 1 Answer
How to load levels with animation GUI 1 Answer
How works loadLevelAsync 0 Answers