目次
SceneManagerの機能拡張
SceneNavigator.cs
using System.Linq;
using UnityEngine.SceneManagement;
using Cysharp.Threading.Tasks;
// SceneManagerに機能を追加した静的クラス
public static class SceneNavigator {
/// <summary>
/// 現在読み込まれている全シーンを取得する
/// </summary>
public static IEnumerable<Scene> GetAllScenes() {
var sceneCount = SceneManager.sceneCount;
for (var i = 0; i < sceneCount; i++) {
yield return SceneManager.GetSceneAt(i);
}
}
/// <summary>
/// シーンが読み込まれているか確認する
/// </summary>
public static bool IsLoaded(string sceneName) =>
GetAllScenes().Any(x => x.name == sceneName && x.isLoaded);
/// <summary>
/// シーンを取得する.存在しない場合は読み込んで取得する
/// </summary>
public static async UniTask<Scene> GetOrLoadSceneAsync(string sceneName) {
if (!IsLoaded(sceneName)) {
await SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
}
return SceneManager.GetSceneByName(sceneName);
}
}
↓ 参考
Sceneに対する処理
SceneExtensions.cs
using UnityEngine;
using UnityEngine.SceneManagement;
public static class SceneExtensions {
/// <summary>
/// 指定シーン内のルートからコンポーネントを取得する
/// </summary>
public static bool TryGetComponentInSceneRoot<T>(this Scene scene, out T result) {
if (!scene.IsValid()) {
throw new System.ArgumentException("Scene is invalid.", nameof(scene));
}
// シーン内のルートオブジェクトを順にチェックする
foreach (GameObject rootObj in scene.GetRootGameObjects()) {
if(rootObj.TryGetComponent(out result)) {
return true;
}
}
result = default;
return false;
}
Sceneアセットをインスペクタで参照する
SceneObject.cs
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[Serializable]
public class SceneObject {
[SerializeField] private string _sceneName;
public static implicit operator string(SceneObject sceneObject) {
return sceneObject._sceneName;
}
public static implicit operator SceneObject(string sceneName) {
return new SceneObject() { _sceneName = sceneName };
}
}
/// ----------------------------------------------------------------------------
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(SceneObject))]
public class SceneObjectEditor : PropertyDrawer {
protected SceneAsset GetSceneObject(string sceneObjectName) {
if (string.IsNullOrEmpty(sceneObjectName)) return null;
for (int i = 0; i < EditorBuildSettings.scenes.Length; i++) {
EditorBuildSettingsScene scene = EditorBuildSettings.scenes[i];
if (scene.path.IndexOf(sceneObjectName) != -1) {
return AssetDatabase.LoadAssetAtPath(scene.path, typeof(SceneAsset)) as SceneAsset;
}
}
Debug.Log("Scene [" + sceneObjectName + "] cannot be used. Add this scene to the 'Scenes in the Build' in the build settings.");
return null;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
var sceneObj = GetSceneObject(property.FindPropertyRelative("_sceneName").stringValue);
var newScene = EditorGUI.ObjectField(position, label, sceneObj, typeof(SceneAsset), false);
if (newScene == null) {
var prop = property.FindPropertyRelative("_sceneName");
prop.stringValue = "";
} else {
if (newScene.name != property.FindPropertyRelative("_sceneName").stringValue) {
var scnObj = GetSceneObject(newScene.name);
if (scnObj == null) {
Debug.LogWarning("The scene " + newScene.name + " cannot be used. To use this scene add it to the build settings for the project.");
} else {
var prop = property.FindPropertyRelative("_sceneName");
prop.stringValue = newScene.name;
}
}
}
}
}
#endif
↓ 参考
Sceneイベントの購読
ObservableSceneEvent.cs
using System;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UniRx;
namespace nitou.SceneSystem {
// SceneManagerのイベントをObserbableに変換する静的クラス
public static class ObservableSceneEvent {
// "activeSceneChanged"イベントをObservableに変換する
public static IObservable<Tuple<Scene, Scene>> ActiveSceneChangedAsObservable() {
return Observable.FromEvent<UnityAction<Scene, Scene>, Tuple<Scene, Scene>>(
h => (x, y) => h(Tuple.Create(x, y)),
h => SceneManager.activeSceneChanged += h,
h => SceneManager.activeSceneChanged -= h);
}
// "sceneLoaded"イベントをObservableに変換する
public static IObservable<Tuple<Scene, LoadSceneMode>> SceneLoadedAsObservable() {
return Observable.FromEvent<UnityAction<Scene, LoadSceneMode>, Tuple<Scene, LoadSceneMode>>(
h => (x, y) => h(Tuple.Create(x, y)),
h => SceneManager.sceneLoaded += h,
h => SceneManager.sceneLoaded -= h);
}
// "sceneUnloaded"イベントをObservableに変換する
public static IObservable<Scene> SceneUnloadedAsObservable() {
return Observable.FromEvent<UnityAction<Scene>, Scene>(
h => h.Invoke,
h => SceneManager.sceneUnloaded += h,
h => SceneManager.sceneUnloaded -= h);
}
}
}
Sceneのエディタ操作関連
// Editor window
// Toobar
※以下を参考にToolBarにシーン切り替えを追加できそう