//tips
//シーン遷移について
シーン遷移について理解を深める。
まず、SceneManager.LoadとSceneManager.Unload が出てくるが、Unityがようしているシーンをコントロールするclassで、Loadが追加、Unloadが削除の意味合いを持つ。
using UnityEngine;
using UnityEngine.SceneManagement;
void ChangeScene()
{
//Playシーンの追加
SceneManager.LoadScene("Play", LoadSceneMode.Additive);
//Titleシーンの削除
SceneManager.UnloadSceneAsync("Title");
}
特にLoadSceneMode.Additiveを使用する場合には上記のようにUnloadが必要になってくる。
LoadSceneMode.Singleの場合は、前のシーンをすべて削除して次のシーンをロードする。一度にロードしておけるシーンは一つだけとなる。一般的に使われるのがこちらで第二引数を指定しなければSingleが使用される。
LoadSceneMode.Singleでシーンをロードすると、基本的にはそれまでのシーン内のオブジェクトはすべて破棄されて消えてしまうので、消したくないオブジェクトがある場合にはDontDestroyOnLoadを使用することとなる。
DontDestroyOnLoadとしたGameObjectは、DontDestroyシーンに移動し、シーンのシングルロード時にも削除されず自分で消さない限りは存在し続けるようになる。
using UnityEngine;
public class Sample: MonoBehaviour
{
void Awake()
{
DontDestroyOnLoad(this.gameobject);
}
}
上記スクリプトを消したくないオブジェクトにつければいい。
DontDestroyOnLoadの一般的な使われ方は、ゲーム全般を管理するGameManagerを作り、それにDontDestroyOnLoadを設定することです。
どのシーンにも必要になるので、このGameManagerを配置する位置が問題になるが、それはプレハブからGameManagerを1度だけ自動的に作成しDontDestroyOnLoadするコンポーネントを作成し、そのコンポーネントを各シーンに設定することで、どのシーンに最初にアクセスされてもGameManagerが存在している状態にする。
using UnityEngine;
public class GameManagerCreator:MonoBehaviour
{
private static bool Loaded {get; set;}
[serializeField]
GameObject[] gameManagerPrefabs=null;
void Awake()
{
if(Loaded)return;
Loaded = true;
foreach(var prefab in gameManagerPrefabs)
{
Gameobject test = Instantiate(prefab);
DontDestroyOnLoad(test);
}
}
}
UnityとしてはこのDontDestroyOnLoadの使用は推奨しておらず、代わりに、すべてのマネージャーを持ったマネージャーシーンを作成し、SceneManager.LoadScene(“path”,LoadSceneMode.Additive) と SceneManager.UnloadScene を使って、ゲームの進行を管理する方法を推している。
LoadSceneで第二引数をLoadSceneMode.Additiveとすると、前のシーンは残ったままでそれに追加して新たなシーンをロードするので、同時に複数のシーンを使用する際に使える。
遷移後に消したいシーンが出てきたら、SceneManager.UnloadSceneAsyncを使う。
DontDestroyOnLoadと同様に、マネージャーシーン以外のシーンからも起動できるようにする便利なので、各シーンにマネージャーシーンを1度だけ自動的にロードするコンポーネントを作成し、
どのシーンから開始しても自動的にマネージャーシーンも一緒にロードされるようにしておく。
複数シーンを使っている場合「他のシーンのオブジェクトを参照する」ということが必須になるが、SceneManagerにあるロードされたシーンを取得する機能で、ほかのシーンのオブジェクトを参照する。
public void OnAccessGameManager()
{
Scene scene = SceneManager.GetSceneByName(“ManagerScene”)
foreach(var rootGameObject in scene.GetRootGameObject())
{
GameManager gameManager = rootGameObject.GetComponent<GameManager>();
if(gameManager != null)
{
Debug.Log(“スコアは”+gameManager.Score+”です”);
break;
}
}
SceneManagerはDontDestroyOnLoadシーンにはアクセスできないので注意が必要。
SceneManagerができる以前の定番は、シングルトンパターンで、Unityのコンポーネントをシングルトンパターンで実装し、それを使って別シーン同士の参照を可能にするというもの。前回記載したが、シングルトンは、どこからでもアクセスできるメリットがある反面、ゲーム中に同じコンポーネントのものは1つだけしか作ってはいけないという制約と一度作ったものの影響力が大きくなりすぎるのでなるべく使われないようにされている。
再度コードを見直し、遷移前のシーンをきちんと認識できていないことが、遷移シーン削除後の問題につながっているのではないかと考え、スクリプトで非表示にしたUIを再表示させるために前のシーンの取得からコードに加えた。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneMoveGO : MonoBehaviour
{
[SerializeField] string myScene = default;
void Start()
{
Invoke("OnSceneMove", 2);
Debug.Log(SceneManager.GetActiveScene().name);
//Debug.Log(currentScene.name);
}
// Update is called once per frame
void Update()
{
}
public void OnSceneMove()
{
//SceneListManager.instance.gameObjects.SetActive(true);
SceneManager.UnloadSceneAsync(myScene);
Scene scene = SceneManager.GetSceneByName("GameObjectMaster");
foreach (var rootGameObject in scene.GetRootGameObjects())
{
SceneListManager gameManager = rootGameObject.GetComponent<SceneListManager>();
if (gameManager != null)
{
gameManager.OnPlay();
}
}
//SceneManager.LoadSceneAsync("GameObjectMaster",LoadSceneMode.Single);
//SceneManager.LoadSceneAsync("GameObjectMaster", LoadSceneMode.Additive);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneListManager : MonoBehaviour
{
public GameObject gameObjects = default;
public Queue<int> queue = new Queue<int>();
public int dequeue ;
//public static SceneListManager instance;
private void Awake()
{
gameObjects.SetActive(true);
}
public void Onregister()
{
// 値を追加
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);
Debug.Log("キューに登録されている数: " + queue.Count);
}
public void OnRemove()
{
gameObjects.SetActive(false);
dequeue = queue.Peek();
//dequeue = Dequeue()
queue.Dequeue();
Debug.Log("Dequeueした値: " + dequeue);
string Scene = dequeue.ToString(); //scenes[1]
SceneManager.LoadSceneAsync(Scene, LoadSceneMode.Additive);
//SceneManager.LoadSceneAsync(Scene, LoadSceneMode.Single);
Debug.Log("キューに登録されている数: " + queue.Count);
}
public void OnPlay()
{
gameObjects.SetActive(true);
}
}
これによりきちんと動作させることができるようになった。