【Unity】Mastering Scene Transitions in Unity: How to Use SceneManager

Created: 2025-12-07Last updated: 2026-07-13

From the title screen to a stage, from a stage to the results screen. Learn the essentials of scene transitions—the backbone of your game's flow—with a beginner-friendly guide centered on the SceneManager class.

"Press Start to jump into the stage," "hit game over and move to the results screen"—your game's flow is built from moving between scenes. And when you try to implement it, you tend to run into walls like "I get a scene-not-found error" or "the screen freezes while loading."

In Unity, moving between scenes is managed by the SceneManager class. This article covers the essential knowledge for scene transitions, from basic loading to asynchronous loading that prevents freezes and lets you show a loading screen.

Scene transition concept: the game progresses by moving from the title screen to a stage, then to the results screen

What You'll Learn

  • Why and how to register scenes in Build Settings
  • Loading scenes by name or build index with LoadScene()
  • Implementing a loading screen (progress bar) with LoadSceneAsync()
  • What's really going on when "progress stops at 0.9"

Sponsored

Adding Scenes to Build Settings

Before you can load scenes from a script, every scene you plan to use must be registered in Build Settings. Skip this step and your scenes may work fine in the editor but throw errors in the actual build because they can't be found.

  1. Select File > Build Settings... to open the Build Settings window.
  2. You'll see a list called Scenes In Build.
  3. Drag and drop every scene file (.unity) your game uses from the Project window into this list.

Each scene added to the list is assigned a build index: 0, 1, 2, and so on. You can load a scene from a script using either this index number or the scene file name (without the extension).

Concept diagram of the Build Settings scene list. Registering scenes in Scenes In Build assigns them build indices 0, 1, 2, letting you load them from scripts by name or number

Tip: By convention, build index 0 is set to the scene that loads first when the game starts (the title screen or a splash screen).

Note: In Unity 6, this window was renamed to File > Build Profiles (scenes are registered in the "Scene List" tab). If an older tutorial says Build Settings, read it as Build Profiles—the registration requirement itself is unchanged.

Basic Scene Loading: LoadScene()

The simplest way to load a scene is the SceneManager.LoadScene() method. To use it, don't forget to add using UnityEngine.SceneManagement; at the top of your script.

LoadScene() runs synchronously. When it's called, game execution stops completely until the current scene is destroyed and the new scene finishes loading. For heavy scenes that take a while to load, the game can appear to freeze for a moment.

Comparison of synchronous vs asynchronous loading. LoadScene freezes the screen until loading finishes, while LoadSceneAsync loads in the background and keeps a loading screen running

Loading by Scene Name

using UnityEngine;
using UnityEngine.SceneManagement; // This is required!

public class TitleScreen : MonoBehaviour
{
    public void OnStartButtonClick()
    {
        // Pass the file name of a scene registered in Build Settings as a string
        SceneManager.LoadScene("GameStage1");
    }
}

Loading by Build Index

using UnityEngine;
using UnityEngine.SceneManagement;

public class GameController : MonoBehaviour
{
    public void GoToTitle()
    {
        // Load the scene at build index 0 (the title screen)
        SceneManager.LoadScene(0);
    }
}
Sponsored

Async Loading and Loading Screens: LoadSceneAsync()

To avoid freezing the game and to show players a "loading screen" that tells them something is happening, you need asynchronous scene loading. The SceneManager.LoadSceneAsync() method loads the scene data mostly in the background, letting you keep updating the screen and running effects while it works.

Note: This doesn't mean the game "never stops at all." The final activation step—creating the new scene's objects and running their Awake calls—happens on the main thread, so a hitch at the moment of the switch can remain. Async loading isn't magically free; think of it as "a mechanism that keeps your loading screen alive during the heavy wait."

LoadSceneAsync() returns an AsyncOperation object that tracks the loading process. By inspecting this object's properties, you can read the loading progress and detect when loading has finished.

Here's a simple loading screen implementation:

using System.Collections;
using TMPro; // For TextMeshPro
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI; // Required for the Slider

public class LoadingScreen : MonoBehaviour
{
    public Slider progressBar;       // UI slider showing load progress
    public TMP_Text progressText;    // UI text showing the percentage

    private bool isLoading; // Guard against double-loading from button mashing

    public void LoadScene(string sceneName)
    {
        if (isLoading) return; // Ignore repeat presses
        isLoading = true;

        // Start a coroutine to load asynchronously
        StartCoroutine(LoadAsynchronously(sceneName));
    }

    IEnumerator LoadAsynchronously(string sceneName)
    {
        // Start loading the scene asynchronously with LoadSceneAsync
        AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);

        // Loop until isDone becomes true
        while (!operation.isDone)
        {
            // progress ranges from 0.0 to 0.9 (0.9 counts as load complete)
            float progress = Mathf.Clamp01(operation.progress / 0.9f);

            // Update the progress bar and text
            progressBar.value = progress;
            progressText.text = (progress * 100f).ToString("F0") + "%";

            // Wait one frame
            yield return null;
        }
    }
}

operation.progress returns 0.9 once loading is 90% complete. The actual scene activation (switching what's displayed) happens in the final 10%, so it's common to calculate progress / 0.9f to display 100%.

Diagram of why progress stops at 0.9: 0 to 0.9 covers data loading, 0.9 to 1.0 covers scene activation, so the displayed progress is calculated by dividing progress by 0.9

Holding the Switch Until You're Ready: allowSceneActivation

The place you actually see "progress stuck at 0.9" is when you use allowSceneActivation. Set it to false and the scene won't switch automatically even after the data finishes loading—progress waits at 0.9 (and isDone never becomes true). This is exactly how the classic "loading complete → PRESS ANY KEY to start" flow is built.

IEnumerator LoadWhenReady(string sceneName)
{
    AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
    operation.allowSceneActivation = false; // Don't switch automatically

    // Once the data is loaded, progress stops at 0.9
    while (operation.progress < 0.9f)
    {
        yield return null;
    }

    // Show "Ready!" and wait for the player's input
    pressAnyKeyText.SetActive(true);
    while (!Input.anyKeyDown)
    {
        yield return null;
    }

    operation.allowSceneActivation = true; // Only now does the scene switch
}

The moment you set allowSceneActivation = true, activation begins, isDone becomes true, and the new scene appears.

Bonus: Good to Know for Later

Once you can implement scene transitions, these are the challenges you'll run into next.

  • Carrying data across scenes: Scores and background music normally disappear when you switch scenes. The classic solution is keeping specific objects alive with DontDestroyOnLoad —covered in the DontDestroyOnLoad article.
  • Additive mode for "stacking" scenes: With LoadScene(name, LoadSceneMode.Additive), you can add another scene without destroying the current one. It's an essential technique for keeping a UI scene resident or streaming a huge map in chunks.
  • More flexible load management: As your project grows, Addressables —a system for centrally managing scene and asset loading—comes into view. The Addressables introduction article gives you an overview.

Summary

Scene transitions are an essential feature for defining your game's structure.

  • Use the SceneManager class to move between scenes.
  • Always add any scene you want to load to Build Settings first.
  • LoadScene(): Simple synchronous loading. The game stops while loading.
  • LoadSceneAsync(): Advanced asynchronous loading. Essential for loading screens.

While players wait, showing a progress bar or gameplay tips helps reduce the stress of waiting. Get comfortable with LoadSceneAsync to level up your game's user experience.