2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Unityでシーン選択と遷移を簡単に!– シーン管理のカスタム方法

Posted at

Unityプロジェクトでのシーン管理は、シーンの遷移や再読み込みなど多くの場所で必要になります。今回は、SceneFieldというカスタムクラスを使って、シーン選択を簡単に行えるようにする方法を解説します。また、シーン遷移を管理するための便利なユーティリティスクリプトや、シーン遷移を扱うためのカスタムスクリプトも紹介します。

GitHub

シーン選択のカスタムクラス: SceneField

SceneFieldは、シーン名をインスペクターで選択できるようにするカスタムクラスです。シーン名を文字列として扱いながらも、プルダウン形式でインスペクターから簡単に選択できるのがポイントです。

using UnityEngine;

[System.Serializable]
public class SceneField
{
    [SerializeField] private string sceneName;

    public string SceneName => sceneName;

    public static implicit operator string(SceneField sceneField)
    {
        return sceneField.SceneName;
    }
}

このクラスでは、sceneNameというプライベートな変数にシーン名を格納します。SceneNameプロパティでその値を取得できるようにしています。また、implicit operator stringを定義することで、このクラスを文字列のように扱うことも可能です。これにより、シーン名を簡単に取得できるようになります。

インスペクターでのシーン選択: SceneFieldPropertyDrawer

SceneField クラスを使ってインスペクターにてプルダウン形式でシーンを選択するためには、Unityエディタ向けのカスタムプロパティドロワーを定義する必要があります。これが SceneFieldPropertyDrawer です。

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(SceneField))]
public class SceneFieldPropertyDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        // シーン名プロパティの取得
        SerializedProperty sceneNameProperty = property.FindPropertyRelative("sceneName");

        // ビルド設定に含まれるシーン名の配列を取得
        string[] scenes = GetSceneNames();

        // 現在のシーン名を取得
        string currentSceneName = sceneNameProperty.stringValue;

        // 現在のシーン名のインデックスを取得
        int currentIndex = -1;
        for (int i = 0; i < scenes.Length; i++)
        {
            if (scenes[i] == currentSceneName)
            {
                currentIndex = i;
                break;
            }
        }

        // プルダウンメニューを表示
        int selectedIndex = EditorGUI.Popup(position, label.text, currentIndex, scenes);

        // 選択されたシーン名を更新
        if (selectedIndex >= 0 && selectedIndex < scenes.Length)
        {
            sceneNameProperty.stringValue = scenes[selectedIndex];
        }
    }

    private string[] GetSceneNames()
    {
        var sceneList = new System.Collections.Generic.List<string>();
        foreach (var scene in EditorBuildSettings.scenes)
        {
            if (!scene.enabled) continue;
            string scenePath = scene.path;
            string sceneName = System.IO.Path.GetFileNameWithoutExtension(scenePath);
            sceneList.Add(sceneName);
        }
        return sceneList.ToArray();
    }
}
#endif

・シーン名プロパティの取得
FindPropertyRelative("sceneName") を使って、SceneFieldクラス内のsceneNameプロパティにアクセスしています。

・ビルド設定に含まれるシーン名の取得
GetSceneNames()メソッドで、プロジェクトのビルド設定に含まれているすべてのシーン名を取得しています。これは、シーンパスから名前を抽出してリスト化し、配列として返しています。

・プルダウンメニューの表示
EditorGUI.Popup() を使って、インスペクターにプルダウン形式のシーン選択メニューを表示しています。現在のシーン名に応じて、選択中のインデックスを更新し、選択されたシーン名をプロパティに反映します。

シーン遷移の管理: SceneTransitionUtility

次に、シーンの読み込みやリロードなどの操作を行うための SceneTransitionUtility クラスを紹介します。このユーティリティクラスを使うことで、シーン遷移を簡単に実装できます。

using UnityEngine.SceneManagement;

public static class SceneTransitionUtility
{
    // 指定したシーンを同期的に読み込む
    public static void LoadScene(string sceneName)
    {
        if (SceneExists(sceneName))
        {
            SceneManager.LoadScene(sceneName);
        }
        else
        {
            UnityEngine.Debug.LogError($"シーン '{sceneName}' は存在しません");
        }
    }

    // 現在のシーンをリロードする
    public static void ReloadScene()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    // シーンが存在するか確認する
    private static bool SceneExists(string sceneName)
    {
        for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++)
        {
            string path = SceneUtility.GetScenePathByBuildIndex(i);
            string name = System.IO.Path.GetFileNameWithoutExtension(path);
            if (name == sceneName)
            {
                return true;
            }
        }
        return false;
    }
}

・シーンのロード
LoadScene() メソッドを使って、指定されたシーン名が存在するか確認し、存在する場合はシーンをロードします。

・シーンのリロード
ReloadScene() メソッドでは、現在のシーン名を取得してリロードします。シーンのデバッグやテスト時に使えます。

・シーンの存在確認
SceneExists() メソッドで、ビルド設定に含まれるシーン名と一致するかどうかを確認します。

実際にシーン遷移を実行する: CustomSceneManager

最後に、SceneField クラスと SceneTransitionUtility を統合して実際にシーンを遷移させる CustomSceneManager スクリプトを紹介します。

using UnityEngine;

public class CustomSceneManager : MonoBehaviour
{
    [SerializeField] private SceneField sceneToLoad;

    // シーンを同期的に読み込むメソッド
    public void LoadScene()
    {
        SceneTransitionUtility.LoadScene(sceneToLoad.SceneName);
    }

    // 現在のシーンをリロードする
    public void ReloadScene()
    {
        SceneTransitionUtility.ReloadScene();
    }
}

・sceneToLoad には SceneField を使用して、インスペクターで簡単にシーンを選択できるようにしています。
・LoadScene() メソッドでは、選択されたシーン名を使ってシーンを読み込みます。
・ReloadScene() メソッドで、現在のシーンを再読み込みします。

使い方

  1. オブジェクトにアタッチ
    Hierarchyビューで空のゲームオブジェクトを作成し、名前を「SceneManager」などに変更します。このオブジェクトに、先ほど作成した CustomSceneManager スクリプトをアタッチします。

  2. シーンの指定
    インスペクターに SceneToLoad というフィールドが表示されるので、ここにビルド設定に含まれているシーンを指定します。SceneField が有効になっているため、プルダウンメニューからシーンを簡単に選択できます。

プロジェクトに応じてカスタマイズしてください。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?