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); }
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(); }
/// <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); }
/// <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); } }
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); }
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(); }
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); } }
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(); }
/// <summary> シーンをアンロード </summary> public IObservable <Unit> Remove(SceneInstance sceneInfo) { return(UnloadScene(sceneInfo)); }
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); }
/// <summary> 初期シーン登録時のイベント </summary> protected virtual IObservable <Unit> OnRegisterCurrentScene(SceneInstance currentInfo) { return(Observable.ReturnUnit()); }
/// <summary> 初期シーン登録時のイベント </summary> protected virtual UniTask OnRegisterCurrentScene(SceneInstance currentInfo) { return(UniTask.CompletedTask); }
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); } }