無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、数値を入力する二つのノード(例では SpinBox )の大小関係を維持するために、値が変更されたら大小関係を確認して異なれば編集していない方の値を調整するスクリプト例と、それをエディタ拡張のダイアログで使用する例を紹介します。

※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※スクリプトは自己責任でご使用ください。
最小最大を入力するダイアログの作成
今回紹介する大小関係を維持するスクリプトの使用例として、フォントサイズを調整するダイアログをツールメニューからポップアップさせた際に配置されている、最小値と最大値を設定する2つの SpinBox コントロールを対象にします。
それらを配置したダイアログの作成とポップアップの手順については以下の記事を参照してください。
スクリプトを作成
ファイルシステムドックで、追加先のフォルダを右クリックして表示されるメニュー「新規作成」→「スクリプト」で sc_min_max_constraint_handler.gd スクリプトファイルを作成します。
※クラスはデフォルトの Node です。ダイアログではファイル名だけ入力してください。

作成したスクリプトファイルに以下のスクリプトを上書きします。
※詳細はスクリプト内のコメントを参照してください。
@tool
extends Node
class_name ScMinMaxConstraintHandler
## 外部から設定された2つのノードの任意のプロパティの数値の大小関係を維持します。
## エディタ拡張・実行時に動作します。
##
## 大小関係が逆転した場合、編集していない方の値を、大小関係を維持するように変更します。
## 例えば、小さい方が 9, 大きい方が 12 の状態から、大きい方を編集して 8 に下げた時点で
## 小さい方は 8 に変わります。
##
## 使い方の例
## 最小と最大の値を入力する 2 つの SpinBox コントロールの場合、そのどちらかに、
## このスクリプトを割り当て、インスペクタードックに表示される本スクリプトのプロパティ
## (2つのノードと、プロパティ名、数値が変更された際のシグナル名)を指定してください。
## コントロール以外のノードを作って、それにスクリプトを貼り付けて同様の設定をしても動作します。
## 2つのノードのうち小さい値を持つノードをインスペクタードックから指定してください。
@export var node_small: Node = null
## [member node_small] の対象となるプロパティのパスをインスペクタードックから指定してください。
@export var property_path_small: String = "value"
## [member node_small] の値が変わった際のシグナル名をインスペクタードックから指定してください。
## 注意:引数を 0 ~ 9 個持つシグナルに対応しています。
@export var signal_name_small: String = "value_changed"
## 2つのノードのうち大きい値を持つノードをインスペクタードックから指定してください。
@export var node_large: Node = null
## [member node_large] の対象となるプロパティのパスをインスペクタードックから指定してください。
@export var property_path_large: String = "value"
## [member node_small] の値が変わった際のシグナル名をインスペクタードックから指定してください。
## 注意:引数を 0 ~ 9 個持つシグナルに対応しています。
@export var signal_name_large: String = "value_changed"
func _enter_tree():
print("sc_min_max_constraint_handler.gd : _enter_tree called.")
# Called when the node enters the scene tree for the first time.
func _ready():
#print("sc_min_max_constraint_handler.gd : _ready called.")
# 各ノードの値が変更されたときのシグナルと、大小関係を維持するメンバ関数を接続します。
#signal_name_small = "mouse_entered" # 0 個の引数のテスト時にコメント解除してください。マウスオーバーで emit します。
var error_code = node_small.connect(signal_name_small, Callable(self, "_on_node_small_value_changed"))
print("error_code = " + str(error_code))
if error_code == ERR_INVALID_PARAMETER:
print("ERR_INVALID_PARAMETER ")
#print("node_small.is_connected(signale_name_small) = " + str(node_small.is_connected(signal_name_small, Callable(self, "_on_node_small_value_changed"))))
node_large.connect(signal_name_large, Callable(self, "_on_node_large_value_changed"))
return
## [member node_small] の値が変更された際に呼び出される関数です。
## [member node_large] の値よりも大きい値になった場合、
## [member node_small] の値を [member node_large] の値に変更して
## 二つの Node の値を等しくして、大小関係を維持します。
## 注意:引数の個数が 0 ~ 9 個までのシグナルに対応しています。
func _on_node_small_value_changed(_arg1 = null, _arg2 = null, _arg3 = null, _arg4 = null, _arg5 = null, _arg6 = null, _arg7 = null, _arg8 = null, _arg9 = null) -> void:
#print("sc_min_max_constraint_handler.gd : _on_node_small_value_changed called.")
var value_small: int = node_small.get(property_path_small)
var value_large: int = node_large.get(property_path_large)
if value_small > value_large:
node_large.set(property_path_large, value_small)
return
## [member node_large] の値が変更された際に呼び出される関数です。可変長引数にして任意の引数に応じます。
## [member node_small] の値よりも小さい値になった場合、
## [member node_large] の値を [member node_small] の値に変更して
## 二つの Node の値を等しくして、大小関係を維持します。
## 注意:引数の個数が 0 ~ 9 個までのシグナルに対応しています。
func _on_node_large_value_changed(_arg1 = null, _arg2 = null, _arg3 = null, _arg4 = null, _arg5 = null, _arg6 = null, _arg7 = null, _arg8 = null, _arg9 = null) -> void:
#print("sc_min_max_constraint_handler.gd : _on_node_large_value_changed called.")
var value_small: int = node_small.get(property_path_small)
var value_large: int = node_large.get(property_path_large)
if value_small > value_large:
node_small.set(property_path_small, value_large)
return
@tool アノテーションを最初に置くことで、実行時の他に、ツールメニューを選択してダイアログを呼び出す際などのエディタ拡張でも動作するスクリプトとして扱われます。
@tool アノテーションを最初に置かないと、エディタ拡張で表示するダイアログにこのスクリプトを割り当てても空のスクリプトとして扱われ _enter_tree や _ready といった初期化に用いるイベント関数も呼び出されません。
@tool
とは?@ tool“は強力なコード行で、スクリプトの先頭に追加すると、それがエディタ内で実行されるようになります。また、スクリプトの部分ごとにそれをエディタ内で実行するのか、ゲーム内で実行するのか、それとも両方で実行するのかも決めることができます。
エディタでコードを実行する — Godot Engine (4.x)の日本語のドキュメント
疑似的な可変長引数を持つ関数の型について
引数を 0 ~ 9 個まで持つシグナルに対応するために、疑似的な可変長引数をシグナルの受信側メソッドに設定しています。
func _on_node_small_value_changed(_arg1 = null, _arg2 = null, _arg3 = null, _arg4 = null, _arg5 = null, _arg6 = null, _arg7 = null, _arg8 = null, _arg9 = null) -> void:
この疑似的な可変長引数の動作確認ついては、以下の記事を参照してください。
後述するテスト結果は、以下の 0 ~ 1 個までの以下の関数の型を使っていますが、 _arg1 ~ _arg9 までの 0 ~ 9個までの引数へ拡張した後も同様の結果が得られました。
func _on_node_small_value_changed(_arg1 = null) -> void:
スクリプトの適用
作成したスクリプトを、大小関係を設定するコントロールや、そのシーン内に作ったノードに割り当てて、対象の2つのノードなどを設定します。
※例では、大きい方の値を持つ SpinBoxMax ノードに割り当てます。
スクリプトを割り当てたいノードをシーンドックで選択して、シーンドックの右上の「スクリプトをアタッチする」ボタンを押します。

表示された「ノードにスクリプトをアタッチする」ダイアログの「パス」項目の右側にあるフォルダアイコンのボタンを押して、先ほど作成したスクリプトを選択して「読み込み」ボタンを押します。

以上で、選択したノードに先ほど作成したスクリプトを割り当てられました。

そのノードを選択した状態でインスペクタードックの Node Small, Node Large プロパティに、小さい方の値を持つノード、大きい方の値を持つ各ノードをドラッグ&ドロップして設定します。
Property Path には Value、 Signal Name には value_changed が最初から設定されているの SpinBox コントロールの場合は変更する必要はありません。

プラグインが正常に動かない場合は、メニュー「プロジェクト」→「プロジェクト設定」で表示されるダイアログの「プラグイン」タブのそのプラグインの「有効」チェックボックスを OFF にしてから再び ON にすることで、プラグインがいったん終了して初期化されるので試してみてください。

テスト
メニュー「プロジェクト」→「ツール」→「Sc Fit Font Size(追加したメニューアイテム名)」を選択して、先ほど大小関係を設定した SpinBox を持つダイアログを表示します。

ダイアログの左側の SpinBox は、右側の値と同じか小さい値を持つように大小関係を調整されます。
左側の SpinBox の増やすボタンを押して、右側の値より大きくすると、編集していない右側の値が左側の値と同じくなり大小関係を保ちます。

大小関係が守られている範囲で、 SpinBox の値は自由に設定できます。

先ほどと逆に右側の値を、左側の値より小さくすると、編集していない左側の値が自動的に同じ値になり調整されます。

テキストエディットを直接編集して数値を入力して Enter キーで確定した際なども同じように動作します。
※ Enter キーを押さずに OK ボタンなどを押すと、変更前の値がダイアログの変数から得られました。

OK ボタンなどを押すと、それに関連付けた関数が呼び出されます。
その関数内で SpinBox の値を取得すると、入力された値が得られることを print 文で確認できました。

以下は、上記のテスト結果の動画です。
まとめ
今回は、無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、数値を入力する二つのノード(例では SpinBox )の大小関係を維持するために、値が変更されたら大小関係を確認して異なれば編集していない方の値を調整するスクリプト例と、それをエディタ拡張のダイアログで使用する例を紹介しました。
エディタ拡張で利用するために @tool をつけたスクリプトが、今回試したエディタ拡張ではなく、ゲームの実行環境で動作するかの確認については、以下の記事を参照してください。
参照サイト Thank You!
- Godot Engine – Free and open source 2D and 3D game engine
- Control — Godot Engine (4.x)の日本語のドキュメント
- AcceptDialog — Godot Engine (4.x)の日本語のドキュメント
- SpinBox — Godot Engine (4.x)の日本語のドキュメント
- AcceptDialog — Godot Engine (4.x)の日本語のドキュメント #add_cancel_button
- エディタでコードを実行する — Godot Engine (4.x)の日本語のドキュメント
記事一覧 → Compota-Soft-Press
コメント