ゲームエンジン GodotEngine4 で、シーンに配置されているノードに動的にスクリプトを割り当てることができる set_script 関数を用いて、実行中にノードに動的にスクリプトを割り当てた際に発生した、 _ready イベント関数が呼び出されず初期化できない問題と、 _process イベント関数が呼び出されない問題の原因と対処例を紹介します。

※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※スクリプトは自己責任でご使用ください。
前回の記事
前回は、set_script 関数を用いて、実行中に動的にスクリプトを割り当てて動作させる実装例と実行結果を紹介しました。
今回は、set_script 関数でスクリプトを割り当てる際に起きた問題とその対処例を紹介します。
_process が呼び出されない場合の対処例
シーンのノードの set_script メンバ関数は、そのノードに引数で指定したスクリプトリソースを割り当てるだけです。
ノードのプロセスが有効になっていない場合、そのスクリプトで定義した _process イベント関数は呼び出されません。
_process イベント関数が呼び出される状態にするには、ノードの set_process(true) メンバ関数を呼び出す必要があります。
If set to
true, enables processing. When a node is being processed, it will receive a NOTIFICATION_PROCESS on every drawn frame (and the _process() callback will be called if it exists).Note: If _process() is overridden, this will be automatically enabled before _ready() is called.
Note: This method only affects the _process() callback, i.e. it has no effect on other callbacks like _physics_process(). If you want to disable all processing for the node, set process_mode to PROCESS_MODE_DISABLED.
true に設定すると、処理が有効になります。ノードが処理されると、描画されたフレームごとに NOTIFICATION_PROCESS を受け取ります (また、_process() コールバックが存在する場合は呼び出されます)。
注: _process() がオーバーライドされた場合、これは _ready() が呼び出される前に自動的に有効になります。
注: このメソッドは _process() コールバックにのみ影響します。つまり、_physics_process() などの他のコールバックには影響しません。ノードのすべての処理を無効にする場合は、process_mode を PROCESS_MODE_DISABLED に設定します。
Node — Godot Engine (4.4) documentation in English #set_process と Google 翻訳
_ready は呼ばれないので _init で初期化
ノードに set_script メンバ関数割り当てるスクリプトの初期化処理を _ready イベント関数に記述したところ、_ready が呼び出されません。
呼び出されない理由
_ready イベント関数は、そのスクリプトが割り当てられているノードがシーンに追加されたタイミングで呼び出されます。
Called when the node is “ready”, i.e. when both the node and its children have entered the scene tree. If the node has children, their _ready() callbacks get triggered first, and the parent node will receive the ready notification afterwards.
ノードが「準備完了」したとき、つまりノードとその子の両方がシーン ツリーに入ったときに呼び出されます。ノードに子がある場合、その _ready() コールバックが最初にトリガーされ、親ノードはその後準備完了通知を受け取ります。
Node — Godot Engine (4.4) documentation in English #_ready と Google 翻訳
_ready イベント関数が呼ばれない理由は、set_script を呼び出す前に、すでにシーンにノードは追加されているためです。
_init なら呼び出される
set_script メンバ関数の説明によると、その内部で、引数で渡されたスクリプトリソース(例では GDScript )を新たに new で生成するため、そのスクリプトの _init イベント関数が呼び出されます。
Attaches
scriptto the object, and instantiates it. As a result, the script’s _init() is called. A Script is used to extend the object’s functionality.If a script already exists, its instance is detached, and its property values and state are lost. Built-in property values are still kept.
スクリプトをオブジェクトにアタッチし、インスタンス化します。その結果、スクリプトの _init() が呼び出されます。スクリプトは、オブジェクトの機能を拡張するために使用されます。
スクリプトがすでに存在する場合、そのインスタンスは切り離され、そのプロパティ値と状態は失われます。組み込みのプロパティ値は引き続き保持されます。
Object — Godot Engine (stable) documentation in English #set_script と Google 翻訳
このことから set_script を行う可能性があるスクリプトの初期化処理は _ready ではなく _init で行った方が良いでしょう。
Usually used for initialization. For even earlier initialization, Object._init() may be used. See also _enter_tree().
Note: This method may be called only once for each node. After removing a node from the scene tree and adding it again, _ready() will not be called a second time. This can be bypassed by requesting another call with request_ready(), which may be called anywhere before adding the node again.
通常は初期化に使用されます。さらに初期化するには、Object._init() を使用できます。 _enter_tree() も参照してください。
注: このメソッドはノードごとに 1 回だけ呼び出すことができます。シーン ツリーからノードを削除して再度追加した後、_ready() が再度呼び出されることはありません。これは、request_ready() を使用して別の呼び出しを要求することで回避できます。この呼び出しは、ノードを再度追加する前にどこででも呼び出すことができます。
Node — Godot Engine (4.4) documentation in English #_ready と Google 翻訳
Called when the object’s script is instantiated, oftentimes after the object is initialized in memory (through
Object.new()in GDScript, ornew GodotObjectin C#). It can be also defined to take in parameters. This method is similar to a constructor in most programming languages.オブジェクトのスクリプトがインスタンス化されるとき、多くの場合、オブジェクトがメモリ内で初期化された後 (GDScript の Object.new() または C# の new GodotObject を通じて) 呼び出されます。パラメータを取り込むように定義することもできます。このメソッドは、ほとんどのプログラミング言語のコンストラクターに似ています。
Object — Godot Engine (4.4) documentation in English #_init と Google 翻訳
前回、以下の _init と _ready のイベント関数の処理を含むスクリプトを、シーンの Label ノードに set_script メンバ関数で割り当てて、実行しました。
※ label_elased_time.gd で _process も実装した状態で実行しました。
extends Label
## シーン開始時から計測される経過時間です。
var elapsed_time: float = 0.0
func _init():
print("_init called")
return
# Called when the node enters the scene tree for the first time.
func _ready():
print("_ready called")
return
結果は、 _ready イベント関数は呼ばれず、 _init イベント関数だけが呼び出されました。

Hello. Ver.1
Hello. Ver.2
_init called
--- Debugging process stopped ---まとめ
- 実行中にノードに set_script 関数でスクリプトを割り当てても、set_process(true) でプロセスを有効にしないと _process イベント関数が呼び出されないことがわかりました。
- 実行中にノードに set_script 関数でスクリプトを割り当てた場合、すでにノードがシーンに追加されているので _ready イベント関数が呼ばれないので、初期化処理は _init イベント関数で行った方が良いことがわかりました。
参照サイト Thank You!
- Godot Engine – Free and open source 2D and 3D game engine
- Object — Godot Engine (stable) documentation in English #set_script
- Node — Godot Engine (4.4) documentation in English #set_process
- @GDScript — Godot Engine (4.x)の日本語のドキュメント #preload
- GDScript — Godot Engine (4.x)の日本語のドキュメント
- Node — Godot Engine (4.4) documentation in English #_ready
- Object — Godot Engine (4.4) documentation in English #_init
記事一覧 → Compota-Soft-Press

コメント