示例#1
0
        /// <summary>
        /// 1つ前のシーンに遷移.
        /// </summary>
        /// <returns></returns>
        public void TransitionBack()
        {
            // ※ 呼び出し元でAddTo(this)されるとシーン遷移中にdisposableされてしまうのでIObservableで公開しない.

            ISceneArgument argument = null;

            // 遷移中は遷移不可.
            if (TransitionTarget != null)
            {
                return;
            }

            // 履歴の一番最後尾の要素は現在のシーンなので、history[要素数 - 2]が前回のシーンになる.
            if (1 < history.Count)
            {
                argument = history[history.Count - 2];
                history.Remove(argument);
            }

            if (argument != null)
            {
                transitionDisposable = Observable.FromCoroutine(() => TransitionCore(argument, LoadSceneMode.Additive, true, false))
                                       .Subscribe(_ => transitionDisposable = null)
                                       .AddTo(Disposable);
            }
        }
示例#2
0
        /// <summary>
        /// シーン遷移履歴をクリア.
        /// </summary>
        public void ClearTransitionHistory()
        {
            ISceneArgument currentEntity = null;

            // 現在のシーンの情報は残す.
            if (history.Any())
            {
                currentEntity = history.Last();
            }

            history.Clear();

            if (currentEntity != null)
            {
                history.Add(currentEntity);
            }
        }
示例#3
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);
        }
示例#4
0
 /// <summary> シーン引数を設定 </summary>
 public abstract void SetArgument(ISceneArgument argument);
示例#5
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);
            }
        }