- Home /
Can't get LoadLeveAsync to work
I'm trying to make a loading scene with a progress bar using LoadLevelAsync(). I've gone through every single post I could find and none of them are helpful.
The basic problem I've encountered: every single piece of code, including the unity documentation, uses something like this: "yield return level.isDone;". However, I've found that this pauses the game until the level has been loaded, essentially turning LoadLevelAsync() into LoadLevel(). Since what I want is for the game to, you know, actually do something while it's loading (Otherwise I'd use LoadLevel()), this turns most of the code out there useless. This happens in the editor and when built.
I must say I don't really have any experience with CoRoutines and Multithreading, so most of what I've tried was guesswork. From what I've read, I need to have a yield somewhere in the function. I haven't been able to use it in any of the other ways shown in the 5 year+ questions that are somehow on the front page of my google searches (such as having "yield;" at the end of the loop).
Please, could someone tell me how to use LoadLevelAsync() in the only way it makes sense (not pausing the game), and using code that works with Unity 5, and not Unity 3?
My code:
public Text mapName;
public Text loadingStatus;
void Start(){
StartCoroutine(LoadAsync("Map1"));
}
private IEnumerator LoadAsync(string levelName){
AsyncOperation level = Application.LoadLevelAsync(levelName);
mapName.text = "Loading" + levelName + "...";
while(!level.isDone){
loadingStatus.text = Mathf.RoundToInt(level.progress*10)/10 + "%";
yield return level.isDone;
}
}
(ᴵ'ᵐ ᵍᵒⁱⁿᵍ ᵐᵃᵈ, ˢᵉⁿᵈ ʰᵉˡᵖ)
I read quite some time ago about something to do wth loadlevelasync not working in coroutines due to some thread issues. I don't know if that has been solved yet.
You would think that in two engine iterations they would have fixed it, right?
Yeah, that certainly is a failure on Unity's part. Try doing it in fixed update (just as a test) to see if it can at least load the level.
Answer by Bunny83 · Aug 15, 2015 at 11:48 AM
First of all LoadLevelAsync requires Unity pro. You haven't explicitly mentioned if you have Unity pro so just to get that out of the way.
Next thing is the only thing that is actually done asynchronously is the actual loading of the scene. Once the scene is loaded it will switch to the scene and if the scene is big it might still cause some freeze time. If your scene is small the loading might be too fast so it's already loaded within one frame.
I don't have Unity pro myself so i can't test it's behaviour at the moment ^^. What other people have said about "other threads" is nonsense. Every scripting callback (except the new serialization callback) is executed on the main thread. That includes Awake, Start, Update, FixedUpdate, ...
However what could cause problems is when you call that method while another scene is actually loaded which is the case when you're in the first frame of a Unity game. Try placing a "yield return null;" before your LoadLevelAsync call to make it execute the next frame.
You did not set AsyncOperation.allowSceneActivation to false, so Unity will immediately when the scene is loaded switch to the new scene. That switching might cause lag since the old scene will be destroyed and the new scene need to be started up. That switching has to be done in a blocking fashion.
Some more points:
"yield return level.isDone;" actually makes no sense. isDone returns a boolean. Unity's coroutine scheduler only has a few special values which are derived from YieldInstruction. Every other value is treated like "wait for the next frame". So values like: null, true, false, 0, 42, "Hello World" are all treated the same. null is usually the best way to wait for one frame since integer of boolean values will be boxed and cause a memory allocation.
If you want to wait for the level to complete loading you could use "yield return level;" This will pause the coroutine while the level is loading in the background. This will only pause the coroutine. The rest of the game will keep running.
Your while loop should work just fine. isDone will return true once the loading has finished.
If you want to load a scene in the background but not switch to the new scene immediately you have to set "allowSceneActivation" to false right after you called "LoadLevelAsync". When you set it back to true it will switch to the new scene.
I'm pretty sure "progress" is a values between 0 and 1, however since i have Unity free i can't test it ^^.
I think this should work:
void Start()
{
StartCoroutine(LoadAsync("Map1"));
}
private IEnumerator LoadAsync(string levelName)
{
// wait one frame.
yield return null;
AsyncOperation level = Application.LoadLevelAsync(levelName);
mapName.text = "Loading" + levelName + "...";
while(!level.isDone){
loadingStatus.text = Mathf.RoundToInt(level.progress*10)/10 + "%";
yield return null;
}
}
@Bunny83 It works! Thanks. By the way, remember that with Unity 5 these features have been made available in the free version (I've tested it).
Thanks for this. In particular the technique of waiting one frame after the previous scene had loaded before starting the Asyncload operation solved a problem I was having (though i don't really understand why): the Asynchronously loaded scene was always getting automatically activated despite setting allowSceneActivation to false.