【Unity】確認ダイアログを作る


## 概要

"UnityScreenNavigator" + "UniRx" + "UniTask" でシンプルな確認ダイアログを作成する

![confirmModal.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1596227/0f4a3de9-d276-89f1-9729-033bc06be947.gif)

↓ UnityScreenNavigator について

https://github.com/Haruma-K/UnityScreenNavigator/blob/master/README_JA.md

## 実装

確認ダイアログの基底クラス

```ConfirmModalBase.cs
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityScreenNavigator.Runtime.Core.Modal;

namespace nitou.UI {

    public abstract class ConfirmModalBase : Modal, ISelectableContainer {

        [SerializeField] protected TextMeshProUGUI _titleText;
        [SerializeField] protected TextMeshProUGUI _messageText;


        public void SetTitleText(string title) {
            if (_titleText == null) return;
            _titleText.text = title;
        }

        public void SetMessageText(string message) {
            if (_messageText == null) return;
            _messageText.text = message;
        }
    }
}
```

２選択肢の確認モーダル

```TwoChoiceConfirmModal.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UniRx;
using UnityEngine;
using UnityEngine.UI;

namespace nitou.UI {

    public class TwoChoiceConfirmModal : ConfirmModalBase {

        [SerializeField] private Button _yesButton;
        [SerializeField] private Button _noButton;

        // 外部公開用
        public IObservable<Unit> OnYesButtonClicked => _yesButton.onClick.AsObservable();
        public IObservable<Unit> OnNoButtonClicked => _noButton.onClick.AsObservable();

        // いずれかが選択されるまで待機するメソッド
        public UniTask<bool> WaitUntilSelected() {
            // 1本のストリームにまとめる
             return OnYesButtonClicked.Select(x => true)
                .Merge(OnNoButtonClicked.Select(x => false))
                .ToUniTask(useFirstValue: true);
        }
    }
}
```

返り値に Modal を返す拡張メソッド

```ModalContainerExtensions.cs
namespace UnityScreenNavigator.Runtime.Core.Modal{
    public static partial class ModalContainerExtensions {

        public async static UniTask<TModal> PushModal<TModal>(this ModalContainer self,
            string resourceKey, bool playAnimation, string modalId = null, bool loadAsync = true,
            Action<(string modalId, TModal modal)> onLoad = null) where TModal: Modal{

            // Modalの追加
            TModal modal = null;
            await self.Push<TModal>(resourceKey, playAnimation, modalId, loadAsync,
                x => {
                    modal = x.modal;
                    onLoad?.Invoke(x);
                });

            return modal;
        }
    }
}
```

---

呼び出し側

```testMain.cs
[SerializeField] ModalContainer _modalContainer;
private readonly string RESOUCE_KEY = "prefab_confirm_modal";

async void test() {

    // 確認モーダルの表示
    var confirmModal = await _modalContainer.PushModal<TwoChoiceConfirmModal>(RESOUCE_KEY, true,
        onLoad: x => {
            var modal = x.modal;
            modal.SetMessageText("ゲームを開始しますか？");
        });

    // 入力待機
    // (YesButton => true, NoButton => false)
    var isYes = await confirmModal.WaitUntilSelected();
    await ScreenContainer.PopModal(true);

    if (!isYes) return;

    // ゲーム開始処理
    StartInGame();
}
```