C#の経験が浅い私にとってはやはり、ウィンドウメッセージ関係の処理が難しく感じるため、さらに1例取り上げて理解を深めることにする。
下記のコードは以前分析したものと同様に、ウィンドウメッセージによりユーザーに選択をさせる類のものである。前回はユーザーに対してYESかNOの2択を問うものであったが、今回は入力欄から特定範囲の数値を入力させる、または入力をキャンセルさせる機能をもつ。
using System;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class NumberSelectWindow : MonoBehaviour
{
[SerializeField] private TMP_Text messageText;
[SerializeField] private TMP_InputField inputField;
[SerializeField] private Button okButton;
[SerializeField] private Button cancelButton;
private int min;
private int max;
private Action<int> onDecided;
private bool canceled;
public bool IsCanceled => canceled;
// ウィンドウを開く
public void Open(int min, int max, Action<int> callback)
{
this.min = min;
this.max = max;
this.onDecided = callback;
canceled = false;
messageText.text = $"{min}~{max} の数字を入力してください";
messageText.color = Color.white;
inputField.text = "";
inputField.ActivateInputField();
okButton.onClick.RemoveAllListeners();
okButton.onClick.AddListener(OnOk);
cancelButton.onClick.RemoveAllListeners();
cancelButton.onClick.AddListener(OnCancel);
gameObject.SetActive(true);
}
// OKボタン(※再入力機能はここで完結・変更しない)
private void OnOk()
{
if (!int.TryParse(inputField.text, out int value))
{
ShowError("数字を入力してください");
ResetInput();
return;
}
if (value < min || value > max)
{
ShowError($"{min}~{max} の範囲で入力してください");
ResetInput();
return;
}
// 正常入力
onDecided?.Invoke(value);
Close();
}
// キャンセルボタン
private void OnCancel()
{
canceled = true;
Close();
}
private void ShowError(string message)
{
messageText.text = message;
messageText.color = Color.red;
}
private void ResetInput()
{
inputField.text = "";
inputField.ActivateInputField();
inputField.Select();
}
private void Close()
{
gameObject.SetActive(false);
}
}
①[SerializeField] private TMP_InputField inputField;
これは前回無かった要素であり、名前の通り、ユーザーから入力を受け取るためのものである。
②public void Open(int min, int max, Action<int> callback)
引数に関しては前回と同様にcallbackに処理を渡すことにより、内部で指定関数を実行することができる。今回はユーザーにある範囲内の数値を入力させるので、数値範囲の最小値と最大値も引数で指定する必要がある。
③messageText.text = $”{min}~{max} の数字を入力してください”;
ウィンドウに表示するテキスト。$を文字列の前につけておくと、{}で囲んだ変数を埋め込むことができる。
④inputField.ActivateInputField();
これはインプットフィールドにフォーカスし、入力可能な状態にする。ユーザーはわざわざ一度インプットフィールドをクリックしなくても、ウィンドウが表示された時点で数値を入力することができる。
⑤ if (!int.TryParse(inputField.text, out int value))
この条件式を日本語にすると「inputField.text を int に変換しようとして、失敗した場合」となる。したがって、入力されたテキストが整数かどうかを判定できる。さらにout int valueには、int型に変換できた場合にはその結果が格納される仕組みになっている。
以下は呼び出し側
IEnumerator AskNumber()
{
bool decided = false;
int selectedValue = 0;
numberSelectWindow.Open(1, 5, value =>
{
selectedValue = value;
decided = true;
});
// 「決定」または「キャンセル」まで待つ
yield return new WaitUntil(() =>
decided || numberSelectWindow.IsCanceled
);
if (numberSelectWindow.IsCanceled)
{
Debug.Log("キャンセルされました");
yield break; // ここで処理中断
}
// 正常に入力された値
Debug.Log($"選択された値: {selectedValue}");
}