2
3

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】Scene関連のメモ

Last updated at Posted at 2024-01-18

目次

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にシーン切り替えを追加できそう

2
3
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
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?