【Godot】電卓風の数値入力UIの実装方法

この記事では電卓風の数値入力UIの実装方法を紹介します。

電卓風の数値入力UIの実装方法

素材データのダウンロード

今回は日本語フォントを使用するのでこちらのデータをダウンロードしてプロジェクトに追加しておきます。

テーマリソースの作成

日本語フォントを使用するためにテーマリソースを作成します。

ファイルシステムを右クリックして「新規リソース」を選び、Themeリソースを作成します。

テーマリソースのファイル名は何でもよいですが、ここでは「new_theme.tres」としておきます。

作成した “new_theme.tres” をダブルクリックして、インスペクターから「Theme > Default Font > [空]」をクリックして「新規 DynamicFont」を選びます。

作成した「DynamicFont」をクリックするとフォント設定が表示されるので「Font > Font Data > [空]」をクリックして「読み込み」を選びます。

日本語フォント “mplus-1c-regular.ttf” を読み込みます。

フォントサイスを少し大きくしたいので、「Settings > Size」の値を「24」に変更しておきます。

テーマビューの「保存」をクリックして変更を保存しておきます。

シーンの作成

今回はUIなので、Controlノード (ユーザーインターフェース) を作成します。

名前は「Main」に変更しておきます。

UIノードのレイアウト

各UIノードを作成する前にレイアウトの完成図を示しておきます。

外枠に「VBoxContainer」を作成し、その中に、「Label」「GridContainer」「Button」の順で配置します。
そして「GridContainer」の中には、数字入力の「Button」を配置します。

VBoxContainerの作成

まずは VBoxContainer を作成します。このノードは子となるノードを縦方向に並べるコンテナとなります。

Labelの作成

次に入力した数値を表示する Label ノードを作成します。

そしてインスペクターから「Control > Theme > Theme > [空]」をクリックして「読み込み」を選びます。

先程作成したテーマ “new_theme.tres” を開きます。

GridContainer の作成

ボタンをグリッド(格子)上に並べるために GridContainerを作成します。

そしてインスペクターから「GridContainer > Columns」の値を「3」に設定します。

これで横のサイズが「3つ」のグリッドコンテナとなります。

数字ボタンの配置

Buttonノードを配置していきます。

電卓のような配置とするので、まずは一段目に「7」「8」「9」と並ぶようにします。
GirdContainerの下にButtonノードを作成し、ノード名は「Button7」にリネームします。

そしてインスペクターから「Control > Theme > Theme > [空]」をクリックして、「読み込み」を選びます。

“new_theme.tres” を開きます。

テーマを設定したら「Button > Text」に「7」を指定します。

このButtonノードをもとに各数字ボタンを作成するために複製を行います。

複製するには「Button7」ノードを選択した状態で「Ctrl+D (macOSの場合は Cmd+D」でボタンを複製します。

10個ほど複製して、以下のようにリネームします。

  • Button8: Text「8」
  • Button9: Text「9」
  • Button4: Text「4」
  • Button5: Text「5」
  • Button6: Text「6」
  • Button1: Text「1」
  • Button2: Text「2」
  • Button3: Text「3」
  • Button0: Text「0」
  • ButtonClear: Text「C」

ここまでできたら Mainノードを選んでスクリプトを作成し、

スクリプトには以下のように記述します。

extends Control

# 入力可能な最大桁数
const MAX_DIGIT = 4	 # 最大4文字まで

# 入力した数値を表示するラベル
onready var label = $VBoxContainer/Label

func _ready() -> void:
	for i in range(10):
		# 0〜9の数値ボタンのノードを取得する
		var name = "VBoxContainer/GridContainer/Button%d"%i
		var btn:Button = get_node(name)
		# シグナルを接続する
		# ・第1引数: シグナル名
		# ・第2引数: 接続する関数を持つインスタンス
		# ・第3引数: 接続する関数名
		# ・第4引数: 関数に渡すパラメータ
		btn.connect("pressed", self, "_on_NumberButton_pressed", [i])

func _on_NumberButton_pressed(num) -> void:
	# 数値ボタンの入力
	if label.text.length() < MAX_DIGIT:
		# 最大桁数より小されば文字を追加
		label.text += "%d"%num

0〜9の数値ボタンを get_node() で取得し、connect() でボタンにシグナルを接続しています。”connect()” 関数の説明は以下のとおりです

・第1引数: シグナル名
・第2引数: 接続する関数を持つインスタンス
・第3引数: 接続する関数名
・第4引数: 関数に渡すパラメータ(引数)

“pressed” シグナル (ボタンを押した) を受け取ったら、”_on_NumberButton_pressed()” を呼び出し、引数はボタンの数字となります。

では実行して、数字が4桁まで指定できることを確認します。

入力した数値のクリアボタンの実装

「ButtonClear」ノードを選択して、シグナル「pressed」を作成します。

接続した関数は以下のように記述します。

func _on_ButtonClear_pressed() -> void:
	# 入力文字を消す
	label.text = ""

実行して入力した数値が消えることを確認します。

問題文と正解判定の実装

最後に問題文と正解判定の実装を行います。

まずはボタンを複製(右クリックして「複製」または Ctrl+Dなど)します。
そしてノード名を「ButtonEnter」にリネームします

これを確定ボタンとします。
GridContainerと同じ階層の下に配置したいので、以下の手順でうまく移動させます。

  1. ButtonEnter を GridContainer の「上」に移動させる (Ctrl+↑キーで移動させてドラッグ&ドロップする)
  2. GridContainer を ButtonEnter の「上」に移動させる

いきなり下に移動させることはできないようなので、”ButtonEnter” を上に移動させてから “GridContainer” をその上に移動させることで “ButtonEnter” を “GridContainer” と同階層の下に移動させることができます。

そして移動させた “ButtonEnter” ノードのインスペクタから Text を「決定」とします。

これでUIのレイアウトが電卓っぽい見た目となりました。

次に Mainノードを選択して、その直下に Labelノードを2つ作成します。

  • Label2: 問題文テキスト
  • Label3: 正解判定結果テキスト

このテキストは数値入力とは別の部分に配置したいので、ルートノードに直接ぶら下げるようにしました

そして、それぞれにテーマを設定 (Control > Theme > Theme > [空] をクリックして「読み込み」で “new_theme.tres” を読み込む) しておき、日本語を表示できるようにしておきます。

“Label2″ の Textには「ヒント:チョコレート」、”Label3” には「4桁の数値を入力」と指定します。

このようなレイアウトとなりました。

なお、数値入力ノードの “VBoxContainer” をマウス操作で移動させる場合、選択モードで移動させると子ノードが選択されて移動させにくいため「移動モード」を選ぶと移動させやすいです。

各種ボタンのシグナル設定

“ButtonEnter” に “pressed” シグナルを接続します。
シグナル関数は以下のように記述します。

onready var label3 = $Label3 # 正解判定結果テキスト

...

func _on_ButtonEnter_pressed() -> void:
	# 正解判定
	if label.text == "0214":
		label3.text = "正解!"
	else:
		label3.text = "不正解"

“Label3″ に正解判定のテキストを設定したいので、”onready” で “label3” 変数に格納しておきます。

答えは、バレンタインデーの日付 “0214” となります。

それと シグナル関数 “_on_ButtonClear_pressed()” (消去ボタン) を以下のように修正しておきます。(正解判定のテキストも消しておく)

func _on_ButtonClear_pressed() -> void:
	# 入力文字を消す
	label.text = ""
	# 正解判定の文字も消しておきます
	label3.text = ""

では、実行して動作を確認します。

完成プロジェクト

今回作成したプロジェクトを添付しておきます。

参考

今回の記事を書くにあたって以下の記事を参考にしました

シグナルの設定方法について詳しく書かれているので、参考になります。