- Home /
Loading screen bar not loading.
Problem: I am making a loading screen for my rts game. I have a simple Main menu with a button on it, and when clicked, it will load a scene using LoadSceneAsync and then it will start 2 coroutines, the first one is for the scene loading progress, and the second one is for my world generation loading bar:
float totalSceneProgress = 0;
float[] totalObjectProgress = { 0, 0, 0 };
IEnumerator GetSceneLoadProgress()
{
for (int i = 0; i < scenesLoading.Count; i++)
{
while (!scenesLoading[i].isDone)
{
totalSceneProgress = 0;
foreach (AsyncOperation op in scenesLoading)
{
totalSceneProgress += op.progress;
}
totalSceneProgress = Mathf.Clamp01((totalSceneProgress / scenesLoading.Count) / 0.9f);
yield return null;
}
}
}
IEnumerator GetTotalProgress()
{
float totalProgress = 0;
while (!MapGrid.doneLoading)
{
for (int i = 0; i < totalObjectProgress.Length; i++)
{
switch (i)
{
case 0:
totalObjectProgress[i] = MapGrid.mapLoading / mapLoadingMax;
print(MapGrid.mapLoading + " / " + mapLoadingMax);
break;
case 1:
totalObjectProgress[i] = MapGrid.terrainLoading / mapLoadingMax;
break;
case 2:
totalObjectProgress[i] = MapGrid.resourceLoading / mapLoadingMax;
break;
}
}
totalProgress = (totalObjectProgress[0] + totalObjectProgress[1] + totalObjectProgress[2] + totalSceneProgress) / (totalObjectProgress.Length + 1);
slider.value = totalProgress;
yield return null;
}
print(totalObjectProgress[0]);
yield return new WaitForSeconds(0.5f);
loadingPage.SetActive(false);
}
I noticed a problem though, when I generate my map, I use for loop in a function. For example, my code will loop 40,000 times for map width and height of 200 and 200. Each loop, I have set a variable to be added one everytime it looped once. In my coroutine, I am trying to access these numbers and getting a percentage out of them. I thought if I did that, the bar will go up, however it only stopped at 25 percent (Meaning it only accounted the scene loading progress) and the rest of the 75 (Which I set to be the map generation progress) won't show and the game will just load when its done without making the bar go up.
I have tested this and found that in my coroutine, the numbers in totalObjectProgress will always stay at 0 despite my other script updating the numbers.
I tried to debug this by making my script print out the index each time it adds 1 to the progress variable, as I suspected, instead of working like an update method, it lags, and then suddenly my console is filled with 40,000 print messages all at once.
Is there a way to make my map generation not freeze the game and will go up one by one or at least slow enough so it does not try to load in all at once and freeze the game.
Answer by bdubbert · Oct 29, 2021 at 07:54 PM
Coroutines in Unity are not true coroutines: they still run on the main Unity thread and are updated every update cycle. That means if a process hangs the main Unity thread (for example, a large FOR loop) then the execution of the coroutines will hang as well.
You have a few options here -
Break up your for loop across several update cycles by only doing parts of the for loop each update, or put it in a unity coroutine and split up chunks of the calculation with a
yield return
Use an actual multithreaded approach. C# makes it pretty easy to create and launch threads. Make sure that you are putting your for loop on a separate thread though - if you put your progress bar on a different thread the progress bar script will run correctly but the UI itself will never update to reflect it until the main thread becomes unstuck again.
Thank you for your response, I have placed my for loops of the initialization of my map into a coroutine, and yield return null each 200 loops, and also I will now update the loading bar using the Unity update method.