Scene遷移 / gameObjectが属しているSceneを得る

UnityでのSceneを遷移は
```SceneManager.LoadSceneAsync(sceneName);```
のように行いますが、初めに各種マネージャーなどメインsceneを作っておき、
```SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);```
のようにシーンを追加するように管理するのが一般的です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/35bb3720-d459-d3de-28aa-db5cfc47a9f8.png)

ここで、```sceneName```という文字列ではなく、Inspectorにsceneそのものを選択できるようにしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/3dc016c8-b107-2e71-d226-de7b7fd9a87c.png)

```ExSceneManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace TmLib
{
    public class ExSceneManager : MonoBehaviour
    {
        public static ExSceneManager Instance { get; private set; }
        public string[] sceneNames { get; private set; }
#if UNITY_EDITOR
        [SerializeField] UnityEditor.SceneAsset[] sceneAssets;
#endif

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

#if UNITY_EDITOR
        private void OnValidate()
        {
            if (sceneAssets != null)
            {
                sceneNames = new string[sceneAssets.Length];
                for (int i = 0; i < sceneAssets.Length; i++)
                {
                    if (sceneAssets[i] != null)
                    {
                        sceneNames[i] = sceneAssets[i].name;
                    }
                }
            }
        }
#endif
    }
}

```
```SceneManager```と名前がついていますが、単にsceneをリストに積めるようにしただけのものです。
```sceneAssets```の値が変化すると```OnValodate()```が呼ばれるので、この中でsceneの文字列リストを生成しています。

実際にこのリストを使用してシーン遷移をするサンプルが以下になります。

**実行するには,あらかじめ各シーンをScene Listに追加しておく必要があります。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/55533bb0-9b0c-7995-67d5-cdf16d970f97.png)

```SceneCtrl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using TmLib;

namespace QiitaTest
{
    public class SceneCtrl : MonoBehaviour
    {
        [SerializeField] List<string> m_addedSceneNamesList = new List<string>();

        // Start is called before the first frame update
        void Start()
        {
            StartCoroutine(loadTestCo());
        }

        // Update is called once per frame
        void Update()
        {
        }

        public bool PushScene(int _sceneId)
        {
            bool ret = false;
            if (ExSceneManager.Instance.sceneNames.Length > _sceneId)
            {
                string sceneName = ExSceneManager.Instance.sceneNames[_sceneId];
                m_addedSceneNamesList.Add(sceneName);
                SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
                ret = true;
            }
            return ret;
        }

        public bool PopScene()
        {
            bool ret = false;
            if (ExSceneManager.Instance.sceneNames.Length > 0)
            {
                string sceneName = m_addedSceneNamesList[m_addedSceneNamesList.Count - 1];
                m_addedSceneNamesList.RemoveAt(m_addedSceneNamesList.Count - 1);
                SceneManager.UnloadSceneAsync(sceneName);
                ret = true;
            }
            return ret;
        }

        public int ClearScene()
        {
            int ret = 0;
            foreach (string sceneName in m_addedSceneNamesList)
            {
                SceneManager.UnloadSceneAsync(sceneName);
                ret++;
            }   
            m_addedSceneNamesList.Clear();
            return ret;
        }

        /// <summary>
        /// 最後にpushしたシーンをunloadして、指定したシーンをloadする
        /// </summary>
        /// <param name="_sceneId"></param>
        public void SwapScene(int _sceneId)
        {
            PopScene();
            PushScene(_sceneId);
        }

        IEnumerator loadTestCo()
        {
            yield return new WaitForSeconds(1.0f);
            PushScene(0); // scene0をロード
            yield return new WaitForSeconds(1.0f);
            SwapScene(1); // scene0を消してscene1をロード
            yield return new WaitForSeconds(1.0f);
            SwapScene(2); // scene1を消してscene2をロード
            yield return new WaitForSeconds(1.0f);
            PushScene(0); // scene0を追加ロード
            yield return new WaitForSeconds(1.0f);
            PushScene(1); // scene1を追加ロード
            yield return new WaitForSeconds(1.0f);
            ClearScene(); // 追加したsceneをすべて削除
            yield return new WaitForSeconds(1.0f);
            PushScene(0); // scene0を追加ロード
            PushScene(1); // scene1を追加ロード
            PushScene(2); // scene2を追加ロード
        }
    }
}

```


<iframe width="560" height="315" src="https://www.youtube.com/embed/tTeG6dmWXkI?si=PkLMl9wH5WFpiZJJ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

また、各gameObjectが度のシーンに属しているかは、
```gameObject.scene.name```で知ることができます。
ただし、```DontDestroyOnLoad()```してしまうと
シーン名もDontDestroyOnLoadになってしまうので注意が必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/83a01aa2-74aa-5cd4-8bb8-8818da77f860.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/5821b614-b556-d994-7582-8e57aa56e612.png)