Scene Manager
Async scene loading with loading screen, progress bar, and minimum load time. Clean transitions between levels.
How to Use
1
Create a persistent 'SceneLoader' object (DontDestroyOnLoad)
2
Attach SceneLoader and optionally assign a loading screen panel
3
Call SceneLoader.Instance.LoadScene("LevelName") to load
4
Hook OnLoadProgress to a UI Slider for a progress bar
5
Set minimumLoadTime to prevent flash-loading on fast hardware
6
Pair with ScreenFader for polished scene transitions
Source Code
C#
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Events;
using System.Collections;
/// <summary>
/// Async scene loader with loading screen support.
/// Provides progress callbacks for loading UI.
/// </summary>
public class SceneLoader : MonoBehaviour
{
public static SceneLoader Instance { get; private set; }
[Header("Loading Settings")]
[SerializeField] private float minimumLoadTime = 1f;
[SerializeField] private GameObject loadingScreen;
[Header("Events")]
public UnityEvent<float> OnLoadProgress;
public UnityEvent OnLoadStarted;
public UnityEvent OnLoadComplete;
private bool isLoading;
private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
/// <summary>
/// Load a scene by name with loading screen.
/// </summary>
public void LoadScene(string sceneName)
{
if (isLoading) return;
StartCoroutine(LoadSceneAsync(sceneName));
}
/// <summary>
/// Load a scene by build index with loading screen.
/// </summary>
public void LoadScene(int buildIndex)
{
if (isLoading) return;
string scenePath = UnityEngine.SceneManagement.SceneUtility.GetScenePathByBuildIndex(buildIndex);
string sceneName = System.IO.Path.GetFileNameWithoutExtension(scenePath);
StartCoroutine(LoadSceneAsync(sceneName));
}
/// <summary>
/// Reload the current scene.
/// </summary>
public void ReloadCurrentScene()
{
LoadScene(SceneManager.GetActiveScene().name);
}
private IEnumerator LoadSceneAsync(string sceneName)
{
isLoading = true;
OnLoadStarted?.Invoke();
if (loadingScreen != null)
loadingScreen.SetActive(true);
OnLoadProgress?.Invoke(0f);
float startTime = Time.unscaledTime;
AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
operation.allowSceneActivation = false;
while (!operation.isDone)
{
// Unity loads to 0.9, then waits for activation
float progress = Mathf.Clamp01(operation.progress / 0.9f);
OnLoadProgress?.Invoke(progress);
if (operation.progress >= 0.9f)
{
// Enforce minimum load time
float elapsed = Time.unscaledTime - startTime;
if (elapsed < minimumLoadTime)
{
yield return new WaitForSecondsRealtime(minimumLoadTime - elapsed);
}
OnLoadProgress?.Invoke(1f);
yield return new WaitForSecondsRealtime(0.1f);
operation.allowSceneActivation = true;
}
yield return null;
}
if (loadingScreen != null)
loadingScreen.SetActive(false);
OnLoadComplete?.Invoke();
isLoading = false;
}
}