無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、
- エディタ編集時に インスペクタードックでメンバ変数の値を変更した際と、
- シーン実行時にボタンを押してメンバ変数の値を変更した際、
どちらのタイミングでも、変数の値が変更された際の setter の関数の処理を実行するスクリプト例と、実行結果を紹介します。
エディタ編集時かシーン実行中かを判定する関数についても紹介します。

※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※スクリプトは自己責任でご使用ください。
前回の記事
前回は、setter 関数を利用して、メンバ変数の値が変更された際に接続済み関数を呼び出す独自のカスタムシグナルを実装したスクリプト例とテストシーンの作成、その実行結果を紹介しました。
https://compota-soft.work/wp1/wp-admin/post.php?post=48700&action=edit
@export でメンバ変数をインスペクタードックに表示させる
前回紹介した getter, setter を設定したメンバ変数 int_value の定義に @export アノテーションを追加して Ctrl + S などで保存します。
@export var int_value: int = 0: set = set_int_value, get = get_int_value
このスクリプトを割り当てられているノードをシーンドックで選択した後、インスペクタードックを確認すると、メンバ変数がインスペクタードックで編集できるようになりました。

@tool アノテーションがないとエディタ編集中は動作しない
インスペクタードックに表示された int_value メンバ変数のプロパティの値を変更してみましょう。
前回、シーン実行時にボタンを押して値を変更すると、 setter に割り当てた set_int_value 関数が呼ばれて print 文が出力されましたが、シーンを実行していないエディタ編集時にインスペクタードックで値を変更しても setter 関数は呼ばれません。
※インスペクタードックでメンバ変数の値を編集する際に setter が呼ばれなくても問題ない場合は、この後に紹介する処理は必要ありません。

@tool アノテーションをスクリプトの冒頭に追記すると、シーンを実行していない、エディタ編集中もスクリプトが実行されるようになります。
しかし、 @tool を追記したスクリプトを保存した直後は、まだエディタから認識されていないのか、プロパティをインスペクタードックで変更しても setter の関数は呼び出されず、 setter の関数内の print 文も出力されません。

@tool アノテーションをスクリプトの冒頭に追記して保存してから、エディタを再起動すると、 @tool 付きのスクリプトと認識されて、プロパティをインスペクターで変更すると setter の関数が呼び出されました。
Godot Engine v4.3.stable.official (c) 2007-present Juan Linietsky, Ariel Manzur & Godot Contributors.
--- Debug adapter server started on port 6006 ---
--- GDScript language server started on port 6005 ---
ERR_INVALID_PARAMETER
set_int_value called. value = 1
get_int_value called. int_value = 0
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
get_int_value called. int_value = 1
int_value を設定
get_int_value called. int_value = 1
set_int_value called. value = 0
get_int_value called. int_value = 1
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
get_int_value called. int_value = 0
int_value を設定
get_int_value called. int_value = 0
set_int_value called. value = 50
get_int_value called. int_value = 0
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
get_int_value called. int_value = 50
対象のプロパティをインスペクタードックで表示していると毎フレーム getter の関数が呼ばれていました。
そのせいで print 文が連続して出力されるので、 getter の関数の print 文はコメントアウトしました。

また、エディタ編集中に、Label.text を変更するスクリプトの処理を行ったため、インスペクタードックで設定している初期値の text プロパティの値が変更されてしまいました。
シーン実行中かエディタ編集中かを判定する is_editor_hint 関数
これを防ぐために、シーン実行中か、エディタ編集中かを判定して、処理を分岐します。
その判定は、is_editor_hint 関数で行います。
Returns
true
if the script is currently running inside the editor, otherwise returnsfalse
. This is useful for@tool
scripts to conditionally draw editor helpers, or prevent accidentally running “game” code that would affect the scene state while in the editor:スクリプトが現在エディタ内で実行されている場合は true を返し、それ以外の場合は false を返します。これは、@tool スクリプトが条件付きでエディター ヘルパーを描画したり、エディター内でシーンの状態に影響を与える「ゲーム」コードが誤って実行されるのを防ぐのに役立ちます。if Engine.is_editor_hint(): draw_gizmos() else: simulate_physics()See Running code in the editor in the documentation for more information.
Note: To detect whether the script is running on an editor build (such as when pressing F5), use OS.has_feature with the
"editor"
argument instead.OS.has_feature("editor")
evaluate totrue
both when the script is running in the editor and when running the project from the editor, but returnsfalse
when run from an exported project.注: スクリプトがエディター ビルドで実行されているかどうか (F5 キーを押したときなど) を検出するには、代わりに OS.has_feature を "editor" 引数とともに使用します。 OS.has_feature("editor") は、スクリプトがエディターで実行されている場合とエディターからプロジェクトを実行している場合の両方で true と評価されますが、エクスポートされたプロジェクトから実行される場合は false を返します。Engine — Godot Engine (4.x)の日本語のドキュメント #is_editor_hint と Google 翻訳
is_editor_hint() を加えたスクリプト
以下は、前述のとおり、以下の機能を前回のスクリプトに追加しました。
- @export アノテーション でメンバ変数をインスペクタードックに表示させる
- @tool アノテーション で、スクリプトを、シーンを実行していないエディタ編集中も動作させる
- is_editor_hint 関数で、シーン実行中に行う処理と、エディタ編集中に行う処理を分岐させる
このスクリプトを上書き保存した後、エディタを再起動してください。
これにより、インスペクタードックで変数の値を編集でき、setter の中で値の変更を知らせるカスタムシグナルを発して、シーン実行中とエディタ編集中の2つのケースに分けて、値が変更されたときのイベント処理を実行できます。
詳細はスクリプト内のコメントを参照してください。
@tool
extends Node
class_name StudySetterGetterSignal
## [member int_value] が変更された際に発せられるシグナルです。
## [param int_value] は設定された新しい値です。
signal int_value_changed(int_value: int)
## setter, getter のテストを行うためのメンバ変数です。
## set, get で setter, getter の関数を割り当てることで
## この変数の値を取得する際は getter, 設定する際は setter の関数が呼び出されます。
@export var int_value: int = 0: set = set_int_value, get = get_int_value
## [param int_value] の setter 関数です。
func set_int_value(value: int) -> void:
print("set_int_value called. value = " + str(value))
# 値が以前と同じ場合は何もしません。
# getter に割り当てた関数が呼ばれ、その戻り値と value を比較します。
if int_value == value:
return
int_value = value # 値を設定
int_value_changed.emit(value) # シグナルを発します。
return
## [param int_value] の getter 関数です。
func get_int_value() -> int:
# インスペクタードックにプロパティを表示している際に毎フレーム呼ばれるので print 文はコメントアウトします。
#print("get_int_value called. int_value = " + str(int_value))
return int_value
## $ButtonRandom を押した回数です。
var button_random_count: int = 0
# Called when the node enters the scene tree for the first time.
## シーンに、このスクリプトを割り当てたノードが。配置された直後に呼び出されるイベント関数です。
func _ready():
# ラベルの表示を更新します。
update_labels()
# [signal StudySetterGetterSignal.int_value_changed] をメンバ関数と接続します。
# シグナルは、エディタのノードドックから接続することもできます。
int_value_changed.connect(Callable(self, "_on_int_value_changed"))
return
## [signal StudySetterGetterSignal.int_value_changed] シグナルに接続した関数です。
## シグナルが発せられると呼び出されます。
func _on_int_value_changed(_int_value: int) -> void:
## インスペクタードックから変更された際などに呼ばれた場合は、シーンを実行していないので表示の更新をしません。
## シーンを実行していない、エディタで Label.text を更新すると、
## インスペクタードックで設定している text プロパティが変化してしまいます。
if Engine.is_editor_hint():
# Code to execute when in editor. エディターで実行するコード。
print("Engine.is_editor_hint() == true")
## シーン実行中は、Label.text の表示の更新を行います。
## シーンを実行している場合は、実行中の Label.text だけが変化して、
## インスペクタードックでの設定は変化しません。
if not Engine.is_editor_hint():
# Code to execute when in game. ゲーム中に実行するコード。
print("Engine.is_editor_hint() == false")
# ラベルの表示を更新します。
update_labels()
return
## $LabelIntValue のテキストを更新します。
func update_labels() -> void:
# int_value の値を表示するラベルのテキストを更新します。
# このタイミングで getter 関数が呼び出されます。
$LabelIntValue.text = "int_value = %s" % [str(int_value)]
# button_random_count の値を表示するラベルのテキストを更新します。
$LabelCount.text = "( %s 回目)" % [str(button_random_count)]
return
## $ButtonRandom の [Signal BaseButton.button_up] が発せられた際に呼び出される受信側メソッドです。
func _on_button_random_button_up():
# ボタンを押した回数を 1 増やします。
# 先に int_value の値を変えてしまうと、 update_labels が
# button_random_count を加算する処理よりも早く呼ばれてしまい
# 回数が1回遅く表示されます。 (0, 0, 1, 2,...)
button_random_count += 1
# 1 ~ 9 の値を加算します。
# このタイミングで setter 関数が呼び出されます。
# また、 setter 関数の内部で [signal StudySetterGetterSignal.int_value_changed] が発せられます。
var random_value: int = randi_range(1, 9)
int_value += random_value
# 直前に加算された値を更新します。
$LabelRandomValue.text = "+ %s" % [str(random_value)]
return
テスト
エディタ編集中に、インスペクタードックで、メンバ変数のプロパティを編集すると、@tool アノテーション により、エディタ編集中でも setter などのスクリプトの処理が動作します。
そして、 is_editor_hint 関数により、エディタ編集中であることを判別した print 文が出力されました。

int_value を設定
set_int_value called. value = 6
Engine.is_editor_hint() == true
次に、 F6 キーでシーンを実行します。
Random ボタンを押して、メンバ変数の値を変更すると、 setter が呼び出され、その中でカスタムシグナルが発せられ、接続している画面表示の関数が呼ばれました。
このとき、 is_editor_hint 関数によって、シーン実行中であると判定して、シーン実行中に行う Label.text の値を書き換える、画面表示の更新の処理が行われました。

set_int_value called. value = 6
set_int_value called. value = 9
Engine.is_editor_hint() == false
set_int_value called. value = 15
Engine.is_editor_hint() == false
set_int_value called. value = 23
Engine.is_editor_hint() == false
set_int_value called. value = 27
Engine.is_editor_hint() == false
set_int_value called. value = 33
Engine.is_editor_hint() == false
set_int_value called. value = 42
Engine.is_editor_hint() == false
set_int_value called. value = 46
Engine.is_editor_hint() == false
set_int_value called. value = 47
Engine.is_editor_hint() == false
まとめ
今回は、無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、エディタ編集時に インスペクタードックでメンバ変数の値を変更した際と、シーン実行時にボタンを押してメンバ変数の値を変更した際、どちらのタイミングでも、変数の値が変更されたイベント処理を実行するスクリプト例と、実行結果を紹介しました。
エディタ編集時かシーン実行中かを判定する関数についても紹介しました。
参照サイト Thank You!
- Godot Engine – Free and open source 2D and 3D game engine
- GDScript reference — Godot Engine (stable) documentation in English #properties-setters-and-getters
- シグナルの使用 — Godot Engine (4.x)の日本語のドキュメント #custom-signals
- GDScriptプロパティのエクスポート — Godot Engine (4.x)の日本語のドキュメント
- エディタでコードを実行する — Godot Engine (4.x)の日本語のドキュメント
- Engine — Godot Engine (4.x)の日本語のドキュメント #is_editor_hint
- Label — Godot Engine (4.3)の日本語のドキュメント
- PixelMplus(ピクセル・エムプラス) ‥ 8bitビットマップふうフリーフォント – itouhiroはてなブログ
記事一覧 → Compota-Soft-Press
コメント