Unity シーンを管理してトランジションを行う。uGUI
設計
シーン遷移する前にデータ読み込み(通信処理)でコルーチンを使うと思うので、トランジションはIEnumeratorで書く。
とりあえず適当にインターフェイスとか定義
using System.Collections; using UnityEngine; public interface ITransition { IEnumerator onStartTransition(); IEnumerator onEndTransition(); } public abstract class ATransition : MonoBehaviour, ITransition { public abstract IEnumerator onStartTransition(); public abstract IEnumerator onEndTransition(); }
シーンマネージャで各シーンから遷移処理の呼び出し
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; public class SceneManager : MonoBehaviour { #region singleton private static SceneManager instance = null; public static SceneManager Instance { get { if (instance == null) instance = (SceneManager)FindObjectOfType(typeof(SceneManager)); return instance; } } void Awake() { if (SceneManager.Instance != this) Destroy(this); } #endregion [SerializeField] List<ATransition> cache; public T Cache<T>() where T : ATransition { return (T)cache.FirstOrDefault(x => (x as T) != null); } public void Transition(ATransition now, ATransition next) { StartCoroutine(_Transition(now, next)); } private IEnumerator _Transition(ATransition now, ATransition next) { if (now != null) yield return now.onEndTransition(); yield return next.onStartTransition(); Debug.Log(string.Format("transition: end -> {0}, start -> {1}", now == null ? "null" : now.GetType().Name, next.GetType().Name)); } }
遷移用にScene1,Scene2クラス作成
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Scene1 : ATransition { public override IEnumerator onStartTransition() { gameObject.SetActive(true); yield return null; } public override IEnumerator onEndTransition() { gameObject.SetActive(false); yield return null; } public void onclick() { var next = SceneManager.Instance.Cache<Scene2>(); SceneManager.Instance.Transition(this, next); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Scene2 : ATransition { public override IEnumerator onStartTransition() { gameObject.SetActive(true); yield return null; } public override IEnumerator onEndTransition() { gameObject.SetActive(false); yield return null; } public void onclick() { var next = SceneManager.Instance.Cache<Scene1>(); SceneManager.Instance.Transition(this, next); } }
- canvas作成。
- canvas内でCreate Empty > 名前をScene1に変更。その子でボタン作成。
- Scene1にScene1.csをadd compenent。ボタンにonclickを登録。
- canvas内でCreate Empty > 名前をScene2に変更。その子でボタン作成。
Scene2にScene2.csをadd compenent。ボタンにonclickを登録。
適当にCreate Empty > SceneManager.csをadd component。
- SceneManager.csのインスペクターのキャッシュの部分に上記で作成したScene1,Scene2を追加。
- 適当にエントリーポイント用のスクリプト作って開始。※Scene1,Scene2は非アクティブ状態にしておく。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EntryPoint : MonoBehaviour { void Start() { var next = SceneManager.Instance.Cache<Scene1>(); SceneManager.Instance.Transition(null, next); } }
ボタンを押せば遷移するようになる。
シーンにCanvasGroupをadd componentして、alphaのアニメーションなどを行えばそれっぽくなる。
[SerializeField] CanvasGroup group; public override IEnumerator onStartTransition() { gameObject.SetActive(true); yield return startAnimation(); } public override IEnumerator onEndTransition() { yield return endAnimation(); gameObject.SetActive(false); } private IEnumerator startAnimation() { group.blockRaycasts = false; var start = Time.time; var now = start; while (now - start < 1.0f) { group.alpha = Mathf.Lerp(0f, 1f, now - start); yield return null; now = Time.time; } group.alpha = 1f; group.blockRaycasts = true; } private IEnumerator endAnimation() { group.blockRaycasts = false; var start = Time.time; var now = start; while (now - start < 1.0f) { group.alpha = Mathf.Lerp(1f, 0f, now - start); yield return null; now = Time.time; } group.alpha = 0f; group.blockRaycasts = true; }