Hi all, tried to use the loadlevelasync function, as I understand those are useable with the free version of unity 5? If they’re not, well, I guess that would explain it…
I don’t get any errors or anything, the loadbar fills to about 90% and then just…stops,
and I never see my ‘loading complete’ debug statement. So…am I doing something wrong or do I have to get the pro version in order for this to work?
AsyncOperation.isDone will never be true if AsyncOperation.allowSceneActivation is false.
Progress will stop at around 0.9f. You can work around this to do whatever needs to be done before the final load takes place by waiting until progress has reached 0.9f, and end with allowing the scene activation again after you’ve done what you need to prior to that.
Example:
using UnityEngine;
using System.Collections;
public class LoadLevel : MonoBehaviour {
public string level;
private string progress = ""; // Name of scene to load.
private bool isLoading = false;
private bool doneLoading = false;
private bool allowLoading = false;
private void OnGUI() {
GUILayout.BeginVertical("box");
if (!isLoading) {
if (GUILayout.Button ("Begin Load")) {
isLoading = true;
StartCoroutine(LoadRoutine());
}
} else {
if (doneLoading) {
if (GUILayout.Button ("Actually Load")) {
allowLoading = true;
StartCoroutine(LoadRoutine());
}
}
GUILayout.Label(progress);
}
GUILayout.EndVertical();
}
private IEnumerator LoadRoutine() {
AsyncOperation op = Application.LoadLevelAsync(level);
op.allowSceneActivation = false;
while (op.progress < 0.9f) {
// Report progress etc.
progress = "Progress: " + op.progress.ToString();
yield return null;
}
// Show the UI button to actually start loaded level
doneLoading = true;
while(!allowLoading) {
// Wait for allow button to be pushed.
progress = "Progress: " + op.progress.ToString();
yield return null;
}
// Allow the activation of the scene again.
op.allowSceneActivation = true;
}
}
One important thing to note is that anything that happens in Start or Awake on any of the MonoBehaviours in the new scene will not be performed asynchronously. It will only load the things that are in the scene before any code in it is actually run.
Another example of an Awake/Start script in the loaded level that takes a long time to process shows that this is the case:
using UnityEngine;
using System.Collections;
public class WorkAtStart : MonoBehaviour {
public int calculations = 10000;
public int iterations = 10000;
public bool inAwake = true;
public bool inStart = true;
void Start () {
if (inStart == true) {
Calculate("Start");
}
}
void Awake() {
if (inAwake == true) {
Calculate("Awake");
}
}
string debugText = "Calculating...";
private void Calculate(string funcName) {
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
Vector3 calc = Vector3.zero;
// Do some random calculations:
for (int i = 0; i < iterations; i++) {
calc = Vector3.zero;
for (int c = 0; c < calculations; c++) {
calc = calc + Random.onUnitSphere;
}
}
stopwatch.Stop();
Debug.Log (stopwatch.Elapsed);
debugText += "
It’s worth noting, for anyone else who finds this issue, that you cannot finish the LoadLevelAsync() operator if you don’t yield from a MonoBehaviour context.
public IEnumerator Open(string sceneId) {
AsyncOperation op = Application.CanStreamedLevelBeLoaded(sceneId) ? Application.LoadLevelAsync(sceneId) : null;
if (op != null) {
op.allowSceneActivation = true; // Do not defer loading
while (!op.isDone) {
yield return new WaitForSeconds(0.1f);
}
}
}
This above function will never complete beyond 0.9 loaded if it is not yielded into a monobehaviour context, like this:
public void LoadScene(MonoBehaviour context, string sceneId) {
context.StartCoroutine(Open(sceneId));
}
This is a bug in Unity; without the MonoBehaviour to track, the AsyncOperation will never complete; waiting for 0.9 does NOT fix this issue and under no circumstances should you ever use the hack:
while (op.progress < 0.9) { ... }
As a workaround; this code above is incorrect; the new level will not have loaded when the function returns; specifically components and objects in the scene will not have spawned.
If you “yield return loadLevel”, then that’s it for that method; nothing beyond that point will ever get executed. That’s why you don’t see your debug log. Use “yield return null” if you want to continue execution (asynchronously).
As for the progress, I too see the progress reports stop around 90%, but then isDone becomes true shortly after that. So it doesn’t seem like a big deal to me. But note that it may be considerably smoother in a built app than when running within the editor, so be sure to test it there.