コード例 #1
0
        private IObservable <Unit> UnloadScene(SceneInstance sceneInstance)
        {
            if (sceneInstance == null)
            {
                return(Observable.ReturnUnit());
            }

            if (!sceneInstance.Identifier.HasValue)
            {
                return(Observable.ReturnUnit());
            }

            var identifier = sceneInstance.Identifier.Value;

            var observable = unloadingScenes.GetValueOrDefault(identifier);

            if (observable == null)
            {
                observable = Observable.Defer(() => Observable.FromCoroutine(() => UnloadSceneCore(sceneInstance))
                                              .Do(_ => unloadingScenes.Remove(identifier)))
                             .Share();

                unloadingScenes.Add(identifier, observable);
            }

            return(observable);
        }
コード例 #2
0
        private IEnumerator AppendCore(IObserver <SceneInstance> observer, Scenes?identifier, bool activeOnLoad)
        {
            if (!identifier.HasValue)
            {
                yield break;
            }

            SceneInstance sceneInstance = null;

            var diagnostics = new TimeDiagnostics();

            diagnostics.Begin(TimeDiagnostics.Measure.Append);

            var loadYield = LoadScene(identifier.Value, LoadSceneMode.Additive).ToYieldInstruction(false);

            while (!loadYield.IsDone)
            {
                yield return(null);
            }

            if (loadYield.HasError)
            {
                OnLoadError(loadYield.Error, identifier);
            }

            if (loadYield.HasResult)
            {
                sceneInstance = loadYield.Result;

                appendSceneInstances.Add(sceneInstance);

                diagnostics.Finish(TimeDiagnostics.Measure.Append);

                var additiveTime = diagnostics.GetTime(TimeDiagnostics.Measure.Append);

                var message = string.Format("{0} ({1:F2}ms)(Additive)", identifier.Value, additiveTime);

                UnityConsole.Event(ConsoleEventName, ConsoleEventColor, message);

                if (activeOnLoad)
                {
                    sceneInstance.Enable();
                }
            }

            observer.OnNext(sceneInstance);
            observer.OnCompleted();
        }
コード例 #3
0
        /// <summary> 加算シーンをアンロード </summary>
        public void UnloadAppendScene(SceneInstance sceneInstance, bool deactivateSceneObjects = true)
        {
            if (!appendSceneInstances.Contains(sceneInstance))
            {
                return;
            }

            if (deactivateSceneObjects)
            {
                sceneInstance.Disable();
            }

            appendSceneInstances.Remove(sceneInstance);

            // AddTo(this)されると途中でdisposableされてしまうのでIObservableで公開しない.
            UnloadScene(sceneInstance).Subscribe().AddTo(Disposable);
        }
コード例 #4
0
        /// <summary> キャッシュ済みのシーンをアンロード. </summary>
        private void UnloadCacheScene(SceneInstance sceneInstance)
        {
            // ※ 現在のシーンは破棄できんないので再度キャッシュキューに登録しなおす.

            if (sceneInstance == current)
            {
                cacheScenes.Enqueue(sceneInstance);
            }
            else
            {
                if (sceneInstance.Identifier.HasValue)
                {
                    loadedscenes.Remove(sceneInstance.Identifier.Value);
                }

                UnloadScene(sceneInstance).Subscribe().AddTo(Disposable);
            }
        }
コード例 #5
0
        private IEnumerator RegisterCurrentSceneCore()
        {
            if (current != null)
            {
                yield break;
            }

            var scene = SceneManager.GetSceneAt(0);

            while (!scene.isLoaded)
            {
                yield return(null);
            }

            var definition = ScenePaths.FirstOrDefault(x => x.Value == scene.path);
            var identifier = definition.Equals(default(KeyValuePair <Scenes, string>)) ? null : (Scenes?)definition.Key;

            var sceneInstance = UnityUtility.FindObjectsOfInterface <ISceneBase>().FirstOrDefault();

            CollectUniqueComponents(scene.GetRootGameObjects());

            if (sceneInstance != null)
            {
                current = new SceneInstance(identifier, sceneInstance, SceneManager.GetSceneAt(0));

                // 起動シーンは引数なしで遷移してきたという扱い.
                history.Add(new BootSceneArgument(identifier));
            }

            if (current == null || current.Instance == null)
            {
                Debug.LogError("Current scene not found.");

                yield break;
            }

            yield return(OnRegisterCurrentScene(current).ToYieldInstruction());

            yield return(current.Instance.Prepare(false).ToYieldInstruction());

            current.Instance.Enter(false);
        }
コード例 #6
0
        private IEnumerator AppendCore(IObserver <SceneInstance> observer, Scenes?identifier, bool activeOnLoad)
        {
            if (!identifier.HasValue)
            {
                yield break;
            }

            SceneInstance sceneInstance = null;

            var diagnostics = new TimeDiagnostics();

            diagnostics.Begin(TimeDiagnostics.Measure.Append);

            var loadYield = LoadScene(identifier.Value, LoadSceneMode.Additive).ToYieldInstruction();

            yield return(loadYield);

            if (loadYield.HasResult)
            {
                sceneInstance = loadYield.Result;

                diagnostics.Finish(TimeDiagnostics.Measure.Append);

                var additiveTime = diagnostics.GetTime(TimeDiagnostics.Measure.Append);

                UnityConsole.Event(ConsoleEventName, ConsoleEventColor, "{0} ({1}ms)(Additive)", identifier.Value, additiveTime);
            }

            if (activeOnLoad)
            {
                sceneInstance.Enable();
            }

            observer.OnNext(sceneInstance);
            observer.OnCompleted();
        }
コード例 #7
0
        private IEnumerator UnloadSceneCore(SceneInstance sceneInstance)
        {
            var scene = sceneInstance.GetScene();

            if (!scene.HasValue)
            {
                yield break;
            }

            if (SceneManager.sceneCount <= 1)
            {
                yield break;
            }

            UnityAction <Scene> sceneUnloaded = s =>
            {
                if (s.IsValid())
                {
                    if (sceneInstance.Identifier.HasValue)
                    {
                        var identifier = sceneInstance.Identifier.Value;

                        if (loadedscenes.ContainsKey(identifier))
                        {
                            loadedscenes.Remove(identifier);
                        }
                    }

                    if (cacheScenes.Contains(sceneInstance))
                    {
                        cacheScenes.Remove(sceneInstance);
                    }

                    if (onUnloadScene != null)
                    {
                        onUnloadScene.OnNext(sceneInstance);
                    }
                }
            };

            var rootObjects = scene.Value.GetRootGameObjects();

            foreach (var rootObject in rootObjects)
            {
                var targets = UnityUtility.FindObjectsOfInterface <ISceneEvent>(rootObject);

                foreach (var target in targets)
                {
                    yield return(target.OnUnloadSceneAsObservable().ToYieldInstruction());
                }
            }

            AsyncOperation op = null;

            try
            {
                SceneManager.sceneUnloaded += sceneUnloaded;

                op = SceneManager.UnloadSceneAsync(scene.Value);
            }
            catch (Exception e)
            {
                SceneManager.sceneUnloaded -= sceneUnloaded;

                Debug.LogException(e);

                if (onUnloadError != null)
                {
                    onUnloadError.OnNext(Unit.Default);
                }

                yield break;
            }

            while (!op.isDone)
            {
                yield return(op);
            }

            SceneManager.sceneUnloaded -= sceneUnloaded;

            if (onUnloadSceneComplete != null)
            {
                onUnloadSceneComplete.OnNext(sceneInstance);
            }
        }
コード例 #8
0
        private IEnumerator LoadSceneCore(IObserver <SceneInstance> observer, Scenes identifier, LoadSceneMode mode)
        {
            var sceneInstance = loadedscenes.GetValueOrDefault(identifier);

            if (sceneInstance == null)
            {
                var scenePath = ScenePaths.GetValueOrDefault(identifier);

                UnityAction <Scene, LoadSceneMode> sceneLoaded = (s, m) =>
                {
                    if (s.IsValid())
                    {
                        sceneInstance = new SceneInstance(identifier, FindSceneObject(s), s);

                        switch (m)
                        {
                        case LoadSceneMode.Single:
                            loadedscenes.Clear();
                            cacheScenes.Clear();
                            break;
                        }

                        // 初期状態は非アクティブ.
                        sceneInstance.Disable();

                        if (onLoadScene != null)
                        {
                            onLoadScene.OnNext(sceneInstance);
                        }
                    }
                };

                SetEnabledForCapturedComponents(false);

                SceneManager.sceneLoaded += sceneLoaded;

                AsyncOperation op = null;

                try
                {
                    op = SceneManager.LoadSceneAsync(scenePath, mode);
                }
                catch (Exception e)
                {
                    Debug.LogException(e);

                    SceneManager.sceneLoaded -= sceneLoaded;

                    if (onLoadError != null)
                    {
                        onLoadError.OnNext(Unit.Default);
                    }

                    observer.OnError(e);

                    yield break;
                }

                while (!op.isDone)
                {
                    yield return(op);
                }

                SceneManager.sceneLoaded -= sceneLoaded;

                var scene = sceneInstance.GetScene();

                if (scene.HasValue)
                {
                    var rootObjects = scene.Value.GetRootGameObjects();

                    // UniqueComponentsを回収.
                    CollectUniqueComponents(rootObjects);

                    loadedscenes.Add(identifier, sceneInstance);

                    yield return(new WaitForEndOfFrame());

                    if (onLoadSceneComplete != null)
                    {
                        onLoadSceneComplete.OnNext(sceneInstance);
                    }

                    // ISceneEvent発行.
                    foreach (var rootObject in rootObjects)
                    {
                        var targets = UnityUtility.FindObjectsOfInterface <ISceneEvent>(rootObject);

                        foreach (var target in targets)
                        {
                            yield return(target.OnLoadSceneAsObservable().ToYieldInstruction());
                        }
                    }
                }

                SetEnabledForCapturedComponents(true);

                // シーンの初期化処理.
                if (sceneInstance.Instance != null)
                {
                    yield return(sceneInstance.Instance.Initialize().ToYieldInstruction());
                }
            }
            else
            {
                // 初期状態は非アクティブ.
                sceneInstance.Disable();
            }

            observer.OnNext(sceneInstance);
            observer.OnCompleted();
        }
コード例 #9
0
 /// <summary> シーンをアンロード </summary>
 public IObservable <Unit> Remove(SceneInstance sceneInfo)
 {
     return(UnloadScene(sceneInfo));
 }
コード例 #10
0
        private IEnumerator TransitionCore <TArgument>(TArgument sceneArgument, LoadSceneMode mode, bool isSceneBack, bool registerHistory) where TArgument : ISceneArgument
        {
            if (!sceneArgument.Identifier.HasValue)
            {
                yield break;
            }

            // プリロード停止.
            if (preLoadDisposable != null)
            {
                preLoadDisposable.Dispose();
                preLoadDisposable = null;
            }

            TransitionTarget = sceneArgument.Identifier;

            var prevSceneArgument = currentSceneArgument;

            currentSceneArgument = sceneArgument;

            var diagnostics = new TimeDiagnostics();

            var prev = current;

            // 現在のシーンを履歴に残さない場合は、既に登録済みの現在のシーン(history[要素数 - 1])を外す.
            if (!registerHistory && history.Any())
            {
                history.RemoveAt(history.Count - 1);
            }

            //====== Begin Transition ======

            diagnostics.Begin(TimeDiagnostics.Measure.Total);

            yield return(TransitionStart(currentSceneArgument).ToYieldInstruction());

            if (prev != null)
            {
                //====== Scene Leave ======

                diagnostics.Begin(TimeDiagnostics.Measure.Leave);

                // Leave通知.
                if (onLeave != null)
                {
                    onLeave.OnNext(prevSceneArgument);
                }

                // 現在のシーンの終了処理を実行.
                yield return(prev.Instance.LeaveAsync().ToYieldInstruction());

                // PlayerPrefsを保存.
                PlayerPrefs.Save();

                // Leave終了通知.
                if (onLeaveComplete != null)
                {
                    onLeaveComplete.OnNext(prevSceneArgument);
                }

                prev.Disable();

                diagnostics.Finish(TimeDiagnostics.Measure.Leave);
            }

            //====== Scene Unload ======

            // 不要なシーンをアンロード.
            var unloadScenes = loadedscenes.Values
                               // 遷移先のシーンではない.
                               .Where(x => x.Identifier != TransitionTarget)
                               // SceneBaseクラスが存在しない.
                               .Where(x => UnityUtility.IsNull(x.Instance))
                               // キャッシュ対象でない.
                               .Where(x => cacheScenes.All(y => y != x))
                               // 次のシーンのPreload対象ではない.
                               .Where(x => currentSceneArgument.PreLoadScenes.All(y => y != x.Identifier))
                               .ToArray();

            foreach (var unloadScene in unloadScenes)
            {
                yield return(UnloadScene(unloadScene).ToYieldInstruction());

                if (unloadScene.Identifier.HasValue)
                {
                    loadedscenes.Remove(unloadScene.Identifier.Value);
                }
            }

            //====== Load Next Scene ======

            diagnostics.Begin(TimeDiagnostics.Measure.Load);

            // 次のシーンを読み込み.
            var identifier = sceneArgument.Identifier.Value;

            var sceneInfo = loadedscenes.GetValueOrDefault(identifier);

            if (sceneInfo == null)
            {
                var loadYield = LoadScene(identifier, mode).ToYieldInstruction();

                yield return(loadYield);

                if (!loadYield.HasResult)
                {
                    yield break;
                }

                sceneInfo = loadYield.Result;

                if (sceneArgument.Cache)
                {
                    cacheScenes.Enqueue(sceneInfo);
                }
            }

            var scene = sceneInfo.GetScene();

            if (!scene.HasValue)
            {
                Debug.LogErrorFormat("[ {0} ] : Scene情報の取得に失敗しました.", identifier);

                yield break;
            }

            if (sceneInfo.Instance == null)
            {
                Debug.LogErrorFormat("[ {0} ] : SceneBase継承クラスが存在しません.", scene.Value.path);

                yield break;
            }

            SetSceneActive(scene);

            // 前のシーンからの引数を設定.
            sceneInfo.Instance.SetArgument(sceneArgument);

            // 現在のシーンとして登録.
            current = sceneInfo;

            // 次のシーンを履歴に登録.
            // シーン引数を保存する為遷移時に引数と一緒に履歴登録する為、履歴の最後尾は現在のシーンになる.
            if (current.Instance != null)
            {
                history.Add(currentSceneArgument);
            }

            // シーン読み込み後にAwake、Startが終わるのを待つ為1フレーム後に処理を再開.
            yield return(null);

            diagnostics.Finish(TimeDiagnostics.Measure.Load);

            //====== Scene Prepare ======

            diagnostics.Begin(TimeDiagnostics.Measure.Prepare);

            // Prepar通知.
            if (onPrepare != null)
            {
                onPrepare.OnNext(currentSceneArgument);
            }

            // 次のシーンの準備処理実行.
            if (current.Instance != null)
            {
                yield return(current.Instance.Prepare(isSceneBack).ToYieldInstruction());
            }

            // Prepar終了通知.
            if (onPrepareComplete != null)
            {
                onPrepareComplete.OnNext(currentSceneArgument);
            }

            diagnostics.Finish(TimeDiagnostics.Measure.Prepare);

            //====== Unload PrevScene ======

            // キャッシュ対象でない場合はアンロード.
            if (prevSceneArgument == null || !prevSceneArgument.Cache)
            {
                yield return(UnloadScene(prev).ToYieldInstruction());
            }

            //====== Scene Wait ======

            // メモリ解放.
            yield return(CleanUp().ToYieldInstruction());

            // 外部処理待機.
            yield return(Observable.FromMicroCoroutine(() => TransitionWait()).ToYieldInstruction());

            // シーンを有効化.
            sceneInfo.Enable();

            // シーン遷移完了.
            TransitionTarget = null;

            // シーン遷移終了.
            yield return(TransitionFinish(currentSceneArgument).ToYieldInstruction());

            //====== Scene Enter ======

            // Enter通知.
            if (onEnter != null)
            {
                onEnter.OnNext(currentSceneArgument);
            }

            // 次のシーンの開始処理実行.
            if (current.Instance != null)
            {
                current.Instance.Enter(isSceneBack);
            }

            // Enter終了通知.
            if (onEnterComplete != null)
            {
                onEnterComplete.OnNext(currentSceneArgument);
            }

            //====== Report ======

            diagnostics.Finish(TimeDiagnostics.Measure.Total);

            var prevScene = prev.Identifier;
            var nextScene = current.Identifier;

            var total  = diagnostics.GetTime(TimeDiagnostics.Measure.Total);
            var detail = diagnostics.BuildDetailText();

            UnityConsole.Event(ConsoleEventName, ConsoleEventColor, "{0} → {1} ({2:F2}ms)\n\n{3}", prevScene, nextScene, total, detail);

            //====== PreLoad ======

            preLoadDisposable = PreLoadScene(sceneArgument.PreLoadScenes)
                                .Subscribe(_ => preLoadDisposable = null)
                                .AddTo(Disposable);
        }
コード例 #11
0
 /// <summary> 初期シーン登録時のイベント </summary>
 protected virtual IObservable <Unit> OnRegisterCurrentScene(SceneInstance currentInfo)
 {
     return(Observable.ReturnUnit());
 }
コード例 #12
0
 /// <summary> 初期シーン登録時のイベント </summary>
 protected virtual UniTask OnRegisterCurrentScene(SceneInstance currentInfo)
 {
     return(UniTask.CompletedTask);
 }
コード例 #13
0
        public async UniTask RegisterCurrentScene(ISceneArgument sceneArgument)
        {
            if (currentScene != null)
            {
                return;
            }

            var scene = SceneManager.GetSceneAt(0);

            while (!scene.isLoaded)
            {
                await UniTask.DelayFrame(1);
            }

            var definition = ScenePaths.FirstOrDefault(x => x.Value == scene.path);
            var identifier = definition.Equals(default(KeyValuePair <Scenes, string>)) ? null : (Scenes?)definition.Key;

            var sceneInstance = UnityUtility.FindObjectsOfInterface <ISceneBase>().FirstOrDefault();

            CollectUniqueComponents(scene.GetRootGameObjects());

            if (sceneInstance != null)
            {
                currentScene = new SceneInstance(identifier, sceneInstance, SceneManager.GetSceneAt(0));
            }

            if (currentScene == null || currentScene.Instance == null)
            {
                Debug.LogError("Current scene not found.");

                return;
            }

            currentScene.Instance.SetArgument(sceneArgument);

            await OnRegisterCurrentScene(currentScene);

            history.Add(sceneArgument);

            // ISceneEvent.

            var tasks = new List <UniTask>();

            var rootObjects = scene.GetRootGameObjects();

            foreach (var rootObject in rootObjects)
            {
                var targets = UnityUtility.FindObjectsOfInterface <ISceneEvent>(rootObject);

                foreach (var target in targets)
                {
                    var task = UniTask.Defer(() => target.OnLoadScene());

                    tasks.Add(task);
                }
            }

            await UniTask.WhenAll(tasks);

            // Initialize.

            await currentScene.Instance.Initialize();

            // Prepare.

            if (onPrepare != null)
            {
                onPrepare.OnNext(sceneArgument);
            }

            await currentScene.Instance.Prepare(false);

            if (onPrepareComplete != null)
            {
                onPrepareComplete.OnNext(sceneArgument);
            }

            // Enter.

            if (onEnter != null)
            {
                onEnter.OnNext(sceneArgument);
            }

            currentScene.Instance.Enter(false);

            if (onEnterComplete != null)
            {
                onEnterComplete.OnNext(sceneArgument);
            }
        }