Unityでゲームを作成している者です。主に2Dのゲームを作成しています。
ゲーム内で重要なプレイヤー決定を迫るときに、念のため「本当に実行してもよいですか?」という確認メッセージを表示したいことがあります。
例えばですが、セーブデータをロードする場合やゲームを終了するボタンなどの場合です。
プレイヤーが誤って押してしまっている可能性もあるためです。「間違ってセーブ前に押してしまってプレイ中のゲームデータが失われてしまった。」となってしまうと最悪です。
このような時に、「はい、いいえ」とか「OK、キャンセル」みたいなメッセージダイアログが部品としてあると便利なので作成してみました。
画面UI(ゲームオブジェクト)を作成する
C#でソースを作成していく前に、Unityのエディタを使って画面UIを作成していきます。今回作成した「はい、いいえ」のメッセージ部品の手順は以下になります。
- メッセージの土台となるパネルを作成する
- 質問文を表示するテキストを作成する
- 「はい」と「いいえ」をボタンとして作成する
1つずつ方法を記載していきます。
メッセージの土台となるパネルを作成する
右クリック→UI→Panelを選択します。(自分は日本語化してないので、している人は読み替えてください。)

適当な大きさに整えます。

オブジェクトの名前を「YesNoMsg」としました。
更に下記画像の赤四角で囲った部分のチェックを外してActiveをfalseにします。(メッセージが必要になるまでは画面に表示させたくないので、非アクティブにしておきました。)

質問文を表示するテキストを作成する
次に作成したパネルの上に質問文を表示するテキストを配置します。
スタンダードにUI→Textを使うことにしました。

配置したAlignmetを中央ぞろえに変更します。

更にテキストはパネルの上部に配置します。

「はい」と「いいえ」をボタンとして作成する
「はい」と「いいえ」をクリックできるようにするために、UI→Buttonからボタンを作成します。

配置場所はこんな感じです。右を「はい」用のボタン、左を「いいえ」用のボタンとして使用します。

この時点でボタンのラベルを設定してもいいのですが、個人的にスクリプトから設定するほうが汎用性があって好きなので、今回もその方針とします。
例えば「はい、いいえ」ではなく「やる、やらない」という2択にしたい場合でもこのメッセージ部品を使いまわせるようにしたいです。
「はい、いいえ」メッセージを操作するコードを作成する
簡易ですがUIが完成したので、次にメッセージを操作するコードを作成していきます。
早速ですが完成した物は以下になります。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class YesNoMsg : MonoBehaviour
{
public Text confirmText;
public Button yesButton;
public Button noButton;
private Action yesAction;
private Action noAction;
// メッセージを表示する
public void showMsg(string _confirmText, Action _yesAction, Action _noAction)
{
showMsg(_confirmText, "はい", "いいえ", _yesAction, _noAction);
}
public void showMsg(string _confirmText, string _yesButtonText, string _noButtonText, Action _yesAction, Action _noAction)
{
// 質問文を表示するテキストに値を設定
confirmText.text = _confirmText;
// はいボタンのラベルを設定
yesButton.GetComponentInChildren<Text>().text = _yesButtonText;
// いいえボタンのラベルを設定
noButton.GetComponentInChildren<Text>().text = _noButtonText;
// アクティブにする(表示する)
gameObject.SetActive(true);
// ボタンのアクションを設定
yesAction = _yesAction;
noAction = _noAction;
}
// はいボタンの処理
public void onYesClick()
{
yesAction.Invoke();
// 非アクティブにする
gameObject.SetActive(false);
}
// いいえボタンの処理
public void onNoClick()
{
noAction.Invoke();
// 非アクティブにする
gameObject.SetActive(false);
}
}
このソースを先ほど作成したYesNoMsg(パネルのゲームオブジェクト)に設定します。
さらにpublicな変数に各オブジェクトを設定していきます。

ボタンのクリックイベントを登録する
「はい」用のボタンのゲームオブジェクトのオンクリックイベントにYesNoMsgのYesClickメソッドを登録します。

同様に、「いいえ」用ボタンのゲームオブジェクトのオンクリックイベントにYesNoMsgのNoClickメソッドを登録します。
これで一旦完成になります。このメッセージダイアログの呼び出し方のサンプルは以下になります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class test : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
YesNoMsg msg = GameObject.Find("YesNoMsg").GetComponent<YesNoMsg>();
msg.showMsg("ゲームを終了してもよろしいですか?",
() => { UnityEditor.EditorApplication.isPlaying = false; },
() => { });
}
}
showMsgの引数の1番目に質問文を記載します。
2番目に「はい」を押したときに実行したいアクションをラムダ式で記載します。(今回の例だとUnityEditorのテストプレイを終了する)
3番目に「いいえ」を押したときに実行したいアクションをラムダ式で記載します。(今回の例だと何もしない)

「はい、いいえ」メッセージ以外をクリックできないようにする
「はい、いいえ」メッセージを表示させる場合には、ほとんどの場合で他のゲームオブジェクトを操作されたくないはずです。(場合によってはゲーム時間求めたいこともあるかもですね。)
そこで画面全体を透明なパネルで覆ってしまい、メッセージ表示中はそのパネルのRaycastTargetをオンにします。
まず画面上にでっかいパネルを配置します。

そのパネルのアルファを0に設定します。

さらにRaycastTargetをオフにします。

先ほどのYesNoMsg.csを以下のように変更します。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class YesNoMsg : MonoBehaviour
{
public Text confirmText;
public Button yesButton;
public Button noButton;
public GameObject frontPanel;
private Action yesAction;
private Action noAction;
// メッセージを表示する
public void showMsg(string _confirmText, Action _yesAction, Action _noAction)
{
showMsg(_confirmText, "はい", "いいえ", _yesAction, _noAction);
}
public void showMsg(string _confirmText, string _yesButtonText, string _noButtonText, Action _yesAction, Action _noAction)
{
// 質問文を表示するテキストに値を設定
confirmText.text = _confirmText;
// はいボタンのラベルを設定
yesButton.GetComponentInChildren<Text>().text = _yesButtonText;
// いいえボタンのラベルを設定
noButton.GetComponentInChildren<Text>().text = _noButtonText;
// アクティブにする(表示する)
gameObject.SetActive(true);
// ボタンのアクションを設定
yesAction = _yesAction;
noAction = _noAction;
// メッセージ表示中は他を選択できないようにする
frontPanel.GetComponent<Image>().raycastTarget = true;
}
// はいボタンの処理
public void onYesClick()
{
yesAction.Invoke();
// 非アクティブにする
gameObject.SetActive(false);
frontPanel.GetComponent<Image>().raycastTarget = false;
}
// いいえボタンの処理
public void onNoClick()
{
noAction.Invoke();
// 非アクティブにする
gameObject.SetActive(false);
frontPanel.GetComponent<Image>().raycastTarget = false;
}
}
でかいパネルはメッセージの下になるように配置します。

でかいパネルをfrontPanel変数に設定します。

これで、でかいパネルが邪魔で他のゲームオブジェクトをクリックすることができなくなりました。
個人的にはメッセージ表示中は、このでかいパネルのアルファを100くらいまで上げて画面をぼかすことで、メッセージに注目を集めるのが良いかと思います。


コメント