Creating a Loading Bar
In this lesson you will create a loading bar to use when loading different scenes.
We do this so that we can load content in the background of the game while we are carrying out other tasks. Think of examples where you are forced to walk through a small gap. This is used to mask / hide loading of new parts of the scene.
This example will have two scenes. One with a Load Button which when clicked will load the second scene.
The second scene will contain a number of assets so that it will take a longer time to load (just copy and paste objects).
The first scene will have a loading bar that will appear when the load button is clicked.
Create two different scenes.
- Level_1
- Menu
Add multiple objects to the Level_1 scene
Add a button to the Menu scene.
Customise the button.
Go to the EventManager object on the scene
Click Replace with InputSystemUIInputModule
Create a script called LoadingBarManager or similar.
Add this script to a new GameObject called LoadingBarManager.
Open the script and add DontDestroryOnLoad(this) to the start method. This is to keep the LoadingBar Manager working on multiple scenes.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LoadingBarManager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
DontDestroyOnLoad(this);
}
// Update is called once per frame
void Update()
{
}
}
Next we are going to load the next scene using an IEnumerator and LoadSceneAsync to load the scene asynchronously.
We will test this works using Debug.Log before creating the loading bar.
Add the SceneManagement package as shown on Line 4.
Then create a new function called LoadSceneAsync which takes one parameter, a string for the scene name. This is shown on line 14 below.
This function will load the scene and check if it has finished. If it hasn't it will print out a message using Debug.Log.
Line 16 creates a variable to store the asynchronous operation. We use the SceneManager to load this as shown on Line 16.
Next we need a while loop to loop through while the scene is loading. We use the !op.isDone condition to track if the async operation has completed. If it's not we print the message using Debug.Log (later we will change this to update the loading bar. We return null as we don't want to lock up the system while waiting for the async operation to finish.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LoadingBarManager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
DontDestroyOnLoad(this);
}
IEnumerator LoadSceneAsync ( string levelName )
{
AsyncOperation op = SceneManager.LoadSceneAsync(levelName);
while ( !op.isDone )
{
Debug.Log(op.progress);
yield return null;
}
}
}
Next we need to call the function. This could be using a trigger in another part of the code on the scene. In this example we will make a function that will be called when we click a button.
Below we have added a new function on Lines 14-17 that takes the scene name as a parameter and runs the StartCoroutine function. The StartCoroutine function takes one parameter which is the function call that we want to run.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LoadingBarManager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
DontDestroyOnLoad(this);
}
public void LoadLevel (string levelName)
{
StartCoroutine(LoadSceneAsync(levelName));
}
IEnumerator LoadSceneAsync ( string levelName )
{
AsyncOperation op = SceneManager.LoadSceneAsync(levelName);
while ( !op.isDone )
{
Debug.Log(op.progress);
yield return null;
}
}
}
Next we need to link this script up to the button on the scene.
Click + on the OnClick component of the Button.
Add the LoadingBarManager gameobject that contains the LoadingBarManager script.
Then select the LoadLevel function from the menu. This will run this function when the button is clicked on.
Enter the name of the scene to load. In this example Level_1
Now we need to add the scenes to the Build Settings.
Go to File > Build Settings.
Add the scenes. The Menu (or first scene to load should be first).
Close the window.
Run the program. When you click the button you should see some Debug messages. This shows the progress of the asynchronous loading of the scene. The more complex the scene the longer it will take.
Now we need to add a graphical loading bar to the scene.
First add a panel to the scene and position it where you would like. This example has it at the bottom of the scene. Rename this LoadingPanel
Remove the background source image.
Add a slider object to this panel. Rename it LoadingBar
Uncheck interactable.
Change the width and height to match the size of the LoadingPanel.
Delete the Handle Slide Area Object form the LoadingBar.
Change Transition to None.
Open the Fill object of the Fill Area object and change the colour to one that you want to use for the loading bar.
Disable the LoadingPanel by unchecking its active box.
Add the UI package as shown on line 5, as well as two variables for the loading panel and loadingbar as shown on lines 9 and 10.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class LoadingBarManager : MonoBehaviour
{
public GameObject loadingPanel;
public Slider loadingBar;
// Start is called before the first frame update
void Start()
{
DontDestroyOnLoad(this);
}
public void LoadLevel (string levelName)
{
StartCoroutine(LoadSceneAsync(levelName));
}
IEnumerator LoadSceneAsync ( string levelName )
{
AsyncOperation op = SceneManager.LoadSceneAsync(levelName);
while ( !op.isDone )
{
Debug.Log(op.progress);
yield return null;
}
}
}
Select the LoadingBarManager and link the LoadingPanel and LoadingBar to the script.
Modify the LoadingBarManager script to include the following lines by replacing the Debug.Log(op.progress); line of code:
float progress = Mathf.Clamp01(op.progress / .9f);
loadingBar.value = progress;
Finally we need to make the loading panel active.
Add loadingPanel.SetActive(true); to the LoadSceneAsync method.
IEnumerator LoadSceneAsync ( string levelName )
{
loadingPanel.SetActive(true);
AsyncOperation op = SceneManager.LoadSceneAsync(levelName);
while ( !op.isDone )
{
float progress = Mathf.Clamp01(op.progress / .9f);
loadingBar.value = progress;
yield return null;
}
}
Test your program. You should now have a completed Loading Bar.
Below is the completed loading script for use on the Menu scene (or the scene to use when loading another scene):
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class LoadingBarManager : MonoBehaviour
{
public GameObject loadingPanel;
public Slider loadingBar;
public Text loadingText;
public void Start() {
DontDestroyOnLoad(this);
}
public void LoadLevel (string levelName)
{
StartCoroutine(LoadSceneAsync(levelName));
}
IEnumerator LoadSceneAsync ( string levelName )
{
loadingPanel.SetActive(true);
AsyncOperation op = SceneManager.LoadSceneAsync(levelName);
while ( !op.isDone )
{
float progress = Mathf.Clamp01(op.progress / .9f);
//Debug.Log(op.progress);
loadingBar.value = progress;
//loadingText.text = progress * 100f + "%";
yield return null;
}
}
}