Godot4.1(正確には4.1.1)で遭遇したお作法なのか不具合なのかわからない事象のメモ。
なんかシーンファイルが壊れる
https://github.com/godotengine/godot/issues/64330
事象としてはこれっぽい。
調べた感じだと、後述のpreloadによる循環参照にも関係あるっぽい模様。
preloadを使って循環参照すると、instantiateしたノードのスクリプトが空になる
https://github.com/godotengine/godot/issues/76641
経緯としては以下の感じ。
- エディタを開きなおすと時折シーンが壊れて読み込めなくなる(開きなおす前にファイルをいじってはいない)。
- 閉じる前にファイルを開いておいて、エディタを閉じた際に勝手にファイルが更新されないことも確認(=ファイルそれ自体の問題ではない)
- 継承シーンの問題かとも思った(もともと継承シーンが読み込めなくなっていた)が、複製したシーンでも発生。
- とりあえず究明は置いといて動作確認を進めてたら、なんかinstantiateしたオブジェクトのスクリプトが空になっていることが判明。
- エディタ起動時にエラーメッセージが出てたのに気づいたのでぐぐる。結果、どうもpreloadにバグがあるっぽいと判明。
- URL先を読んだ感じ、どうもpreloadというかUIDキャッシュ周りにそもそも問題があるっぽ。
なので、問題の大本はどうも一緒っぽいと思いつつ、解決されるまでは循環参照をしないコードにするしかないかなあ。
子から親の処理を呼ぶ方法
色々ある(autoloadにしたりとか)ようだけど、emit_signal飛ばしてやるのがよさそう。
まず、子にシグナルの定義とemit_signal(シグナル発火)を書く。
シグナルに引数も持たせられる(複数個も可)。
signal fire(arg1, arg2)
func _ready():
emit_signal("fire", 1, 2)
親で呼びたい関数を作り、connectで接続する。
子ノードがすでに存在しているなら${子ノード}.connectで直接connectすればいい。
instantiateしたノードなら、add_childの直前(直後でもいいらしいけど、自分はいまのところ直前派)にconnectしてやる。
子ノード指定でconnectしてないと、親がシグナル拾ってこれないので注意。
var child_scene = preload("res://scenes/child.tscn")
func _fire(arg1, arg2):
print(arg1)
print(arg2)
func _ready():
# 存在する子ノードを使うケース
$child.connect("fire", Callable(self, "_fire")) # すでに存在する子ノードのシグナルを拾う
# 新たにinstantiateした子ノードを使うケース
var child = child_scene.instantiate() # 子ノードをinstantiate
child.connect("fire", Callable(self, "_fire")) # 子ノードのシグナルと接続