Unity

【Unity】SceneManagerの使い方完全ガイド|シーン切り替え・非同期ロード・データ保持・最適化まで解説

この記事でわかること

  • Unityのシーン管理、シーン(Scene)について
  • SceneManagerを使ったシーンの切り替え方法
  • シーンの非同期ロード(ロード画面の作成)
  • DontDestroyOnLoadを使ったデータの引き継ぎ
  • シーン管理の最適化テクニック

Unityのシーン管理とは?

Unityでシーンを管理するには「SceneManager」を使用します。
このクラスを使うと以下のような操作が可能です。

  • シーンを読み込む
  • シーンを追加で読み込む(Additive)
  • 現在のシーン情報を取得する

シーン(Scene)とは?

シーン(Scene)は、ゲームの各シーン(タイトル画面・ステージ・結果画面)を管理する単位です。

・ゲーム全体を1つのシーンで作るのではなく、複数のシーンに分割すると管理しやすい!
・シーンごとにオブジェクトを整理し、ロード・切り替えがスムーズに!

Unity シーン管理の画像

Unityのシーン管理(SceneManager)

シーン(Scene)の作成、保存

① Projectから追加

  1. [Project] → [Scenesフォルダ] → [右クリック] → [Create] → [Scene] → [Scene] を選択
  2. Scenesフォルダ内にシーン(Scene)が追加される
  3. シーン(Scene)名を入力して決定
Unity シーンの作成、保存の画像

シーン(Scene)を追加する方法

シーンを追加しないと、SceneManager.LoadScene()で読み込まないので注意が必要です。

  1. File→Build Settings開く(Unity6だとBuild Profiles
  2. Scenes In Buildに最新シーンをドラッグ&ドロップか「Add Open Scemes」で追加(Unity6だとScene List
  3. シーンの順番を調整し、Build & Run実行可能にする

シーン管理(SceneManager)をスクリプトで制御

シーン管理(SceneManager)の準備

最初にSceneを2つ用意してください。(今回はSampleScene、New Scene)
次にヒエラルキーで右クリックをして空のGameObjectとButtonを1つずつ用意します。
・「右クリック」→「Create Empty」
・「右クリック」→「UI」→「Button – TextMeshPro」

次にスクリプトを作成して先ほどのCreate Emptyにアタッチしてください。

現在のシーンの取得

シーンを跨ぐような変数を用いる場合にシーンによって挙動を変えたいことがあります。そのような時に「SceneManager.GetActiveScene()」を使用すると現在のシーンが取得できます。

using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneManagerScript : MonoBehaviour
{
    [SerializeField] private Scene scene;
    void Start()
    {
        scene = SceneManager.GetActiveScene();
        Debug.Log("現在のシーン名: " + scene.name);
    }
}

実行してみると、現在のシーン名が取得できますね。

シーン(Scene)の切り替え

SceneManager.LoadScene()でシーン切り替え(同期)

シーン切り替えといえばまずは同期のシーン切り替えです。「LoadScene(“シーン名”)」を使用すれば簡単にシーンが切り替わります。
※ボタンはインスペクターでアタッチしておいてください。

using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneChanger : MonoBehaviour
{
    public void ChangeScene()
    {
        SceneManager.LoadScene("New Scene"); // シーン名で指定
    }
}

実行してみると、切り替わりましたね。ヒエラルキーが「New Scene」に変わりました。

LoadSceneAsync()でシーン切り替え(非同期)

シーンのロード時にカクつきを防ぐため、シーン切り替え時には非同期で切り替えをする場合があります。そのような時は「LoadSceneAsync()」を使って非同期でシーンを読み込むのがベストです。

  • 進行状況(operation.progress)をスライダーで表示!
  • ロード画面を見せることで、ユーザー体験を向上!
using System.Collections;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SceneManagerScript : MonoBehaviour
{
    [SerializeField] private string sceneName;
    [SerializeField] private Button changeButton;

    public GameObject loadingScreen;        // ローディング画面
    public Slider progressBar;              // プログレスバー
    public TextMeshProUGUI progressText;    // 進捗率(%表示用)

    // 擬似的に遅延させるための値
    float displayProgress = 0f;

    void Start()
    {
        sceneName = "New Scene";
        changeButton.onClick.AddListener(LoadScene); ;
    }

    // シーンをロードするメソッド(UIボタンから呼び出す)
    public void LoadScene()
    {
        StartCoroutine(LoadSceneAsync(sceneName));
    }

    // 非同期ロード
    IEnumerator LoadSceneAsync(string sceneName)
    {
        // ローディング画面を表示
        loadingScreen.SetActive(true);

        // シーンを非同期でロード開始(allowSceneActivation=false にして最後に切り替え)
        AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
        operation.allowSceneActivation = false;

        while (!operation.isDone)
        {
            // 実際の進捗 (0~0.9 → 0~1に補正)
            float targetProgress = Mathf.Clamp01(operation.progress / 0.9f);

            // 実際の値に近づけていく (時間をかけて滑らかに)
            displayProgress = Mathf.MoveTowards(displayProgress, targetProgress, Time.deltaTime * 0.5f);

            progressBar.value = displayProgress;
            progressText.text = (displayProgress * 100f).ToString("F0") + "%";

            if (displayProgress >= 1f)
            {
                yield return new WaitForSeconds(0.5f); // デモ用に待機
                operation.allowSceneActivation = true;
            }

            yield return null;
        }
    }
}

実行してみると、時間差で移行されましたね。
※今回はデモ用なので実動作はWhileの中身を書き換えてください。

シーン間でデータを保持する方法

DontDestroyOnLoad()を使う

シーンを切り替え時にデータを保持する方法として「DontDestroyOnLoad()」を使います。また、シーン間でデータを保持したい場合はstaticを使いましょう。

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    public int playerScore = 0;

    void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

テキストにデータを保存する

PlayerPrefsやJSONを使うと、シーンが切り替わってもデータを半永続的に保存できる。
※ PlayerPrefsはUnityから非推奨とされています。

シーン管理の最適化

メモリ最適化(不要なオブジェクトの削除)

シーン移行後に不要なオブジェクトを削除することで、メモリ使用量を削減することが可能です。

void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
    Resources.UnloadUnusedAssets();
}

よくあるエラーと解決策

SceneManager.LoadScene()が動作しない

・解決策:Build Settingsにシーンを追加する!
・解決策:シーン名スペルミスをチェック!

シーンが切り替わると変数がリセットされる

・解決策:DontDestroyOnLoad()でデータを保存!
・解決策:PlayerPrefsでデータを保存!

まとめ

・SceneManager.LoadScene()を使えば簡単にシーン移行できる!
・非同期ロード( LoadSceneAsync())を使えるとロード画面ができる!
・DontDestroyOnLoad()を使えばデータを保持可能!
・UIを別シーンに一時的に、シーンロードを高速化!