Exemple #1
0
            public static NavigationLock Acquire(ISceneArgs args)
            {
                if (_lock != null)
                {
                    throw new NavigationFailureException("前回の遷移が終了する前に新しい遷移が開始されました", args);
                }

                return(_lock = new NavigationLock());
            }
Exemple #2
0
 public void Dispose()
 {
     _lock = null;
 }
Exemple #3
0
        private async UniTask <NavigationResult> NavigateCoreAsync(ISceneArgs args, NavigationOption option = NavigationOption.None, IProgress <float> progress = null)
        {
            if (this._currentSubScenesByName.ContainsKey(args.SceneName))
            {
                throw new NavigationFailureException($"{args.SceneName}は既にサブシーンとしてロードされています。サブシーンを通常シーンに変更することはできません。", args);
            }

            using (var internalProgresses = new NavigationInternalProgressGroup(progress, 6))
                using (NavigationLock.Acquire(args))
                {
                    var loadingDisplay = default(ILoadingDisplay);

                    if (this._loadingDisplaySelector != null)
                    {
                        if (this._loadingDisplaysByOption.ContainsKey((int)option))
                        {
                            loadingDisplay = this._loadingDisplaysByOption[(int)option];
                        }
                        else
                        {
                            loadingDisplay = this._loadingDisplaysByOption[(int)option] = this._loadingDisplaySelector.SelectDisplay(option);
                        }
                    }

                    if (loadingDisplay != null)
                    {
                        loadingDisplay.Show();
                    }

                    var cancellationToken = this._currentScene?.SceneLifeCancellationToken ?? new CancellationTokenSource().Token;

                    // まずサブシーンを処理する
                    var subSceneTransitions = await NavigateSubScenesCoreAsync(args, cancellationToken, internalProgresses[0]);

                    internalProgresses[0].Report(1f);

                    NavigationResult activationResult;
                    if (this._scenesByName.ContainsKey(args.SceneName))
                    {
                        // 既にInitialize済みのSceneであればActivateするだけでOK
                        activationResult = this.Activate(args, option);
                    }
                    else
                    {
                        activationResult = await this.LoadAsync(args, cancellationToken, option, internalProgresses[1]);
                    }
                    internalProgresses[1].Report(1f);

                    // ここでダメな場合は既にActivateAsyncでエラーを吐いてるハズ
                    if (activationResult == null || activationResult.NextScene == null)
                    {
                        return(null);
                    }

                    if (option.HasFlag(NavigationOption.Push))
                    {
                        // 新しいシーンをスタックに積む
                        this._navigateHistoryStack.Push(new NavigationStackElement()
                        {
                            SceneName = args.SceneName, TransitionMode = activationResult.TransitionMode
                        });
                    }

                    // 新しいシーンをリセットする
                    await activationResult.NextScene.ResetAsync(args, activationResult.TransitionMode, internalProgresses[2]);

                    internalProgresses[2].Report(1f);

                    if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested)
                    {
                        throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken);
                    }

                    // 新規シーンなら初期化する
                    if (activationResult.TransitionMode.HasFlag(TransitionMode.New))
                    {
                        activationResult.NextScene.Initialize();
                    }

                    // 新規シーンに入る
                    await activationResult.NextScene.EnterAsync(activationResult.TransitionMode, internalProgresses[3]);

                    internalProgresses[3].Report(1f);
                    if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested)
                    {
                        throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken);
                    }

                    // 古いシーンから出る
                    if (activationResult.PreviousScene != null)
                    {
                        await activationResult.PreviousScene.LeaveAsync(activationResult.TransitionMode, internalProgresses[4]);

                        internalProgresses[4].Report(1f);
                    }

                    // 新規シーンに入ったら外部の遷移処理を呼ぶ
                    async UniTask enterNext()
                    {
                        for (var i = 0; i < activationResult.NextScene.RootCanvases.Count; ++i)
                        {
                            activationResult.NextScene.RootCanvases[i].enabled = false;
                        }
                        activationResult.NextScene.RootObject.SetActive(true);

                        await this._afterTransition.OnEnteredAsync(activationResult, activationResult.NextScene.SceneLifeCancellationToken, new Progress <float>());

                        if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested)
                        {
                            throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken);
                        }

                        for (var i = 0; i < activationResult.NextScene.RootCanvases.Count; ++i)
                        {
                            activationResult.NextScene.RootCanvases[i].enabled = true;
                        }
                    }

                    // 古いシーンの遷移処理を呼ぶ
                    async UniTask leavePrevious()
                    {
                        if (activationResult.PreviousScene != null)
                        {
                            await this._afterTransition.OnLeftAsync(activationResult, activationResult.NextScene.SceneLifeCancellationToken, new Progress <float>());

                            if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested)
                            {
                                throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken);
                            }

                            // 上に乗せるフラグが無ければ非アクティブ化
                            if (!option.HasFlag(NavigationOption.Override))
                            {
                                activationResult.PreviousScene.RootObject.SetActive(false);
                            }

                            // Popするならアンロードも行う
                            if (option.HasFlag(NavigationOption.Pop))
                            {
                                // シーンのファイナライズ処理
                                activationResult.PreviousScene.Collapse();

                                // 古いシーンをスタックから抜いてアンロード
                                var popObject = this._navigateHistoryStack.Pop();
                                await UnloadAsync(activationResult.PreviousScene.SceneArgs, activationResult.NextScene.SceneLifeCancellationToken, internalProgresses[5]);

                                if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested)
                                {
                                    throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken);
                                }
                            }
                        }

                        internalProgresses[5].Report(1f);
                    }

                    // 遷移処理は同時に進行
                    await UniTask.WhenAll(
                        enterNext(),
                        leavePrevious(),
                        subSceneTransitions.OnEnteredAsync(activationResult.NextScene.SceneLifeCancellationToken),
                        subSceneTransitions.OnLeftAsync(activationResult.NextScene.SceneLifeCancellationToken));

                    if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested)
                    {
                        throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken);
                    }

                    if (loadingDisplay != null)
                    {
                        loadingDisplay.Hide();
                    }

                    return(activationResult);
                }
        }