はじめに
PeanutsCodeさんのプラットフォーマー制作でGodotを学習中。
前回がPart8、今回はPart9。連続で何かしら発生してます。
環境
- Windows版 Godot Engine Ver.3.5(stable)
- GDScript
現象
プラットフォーマー制作Part9において、ゲームオーバー画面から、Restart / Quit を実行すると下記エラーが発生。実行は続く。
get_tree: Condition "!data.tree" is true. Returned: nullptr
scene/main/node.h:*** @ get_tree()
Game.gd:** @ change_level()
下記コードの get_tree()
が原因。ルートの Game ノードがないのに get_tree()
を実行して怒られていると予想。
func change_level():
if get_tree():
print("change_level() called.")
if current_level < final_level:
print("change to next level.")
level.queue_free()
# 中略
ボツ案
get_tree()
がダメなら is_instance_valid()
でいけるかやってみたところ、
func change_level():
if !is_instance_valid($"/root/Game"): # 追記
return # 追記
if get_tree():
print("change_level() called.")
if current_level < final_level:
print("change to next level.")
level.queue_free()
# 中略
エラー。。
get_node_or_null: Can't use get_node() with absolute paths from outside the active scene tree.
get_node_or_null: アクティブなシーンツリーの外側から絶対パスで get_node() を使用することはできません。
get_path: Cannot get path of node as it is not in a scene tree.
get_path: シーンツリー内にないため、ノードのパスを取得できません。
get_node: (Node not found: "/root/Game" (absolute path attempted from "").
get_node: (ノードが見つかりませんでした。"/root/Game" (絶対パスが "" から試行されました).
get_tree: Condition "!data.tree" is true. Returned: nullptr
get_tree。条件 "!data.tree" は真です。戻り値:nullptr
解決策
上記のボツ案のエラーメッセージにある、『アクティブなシーンツリーの外側から絶対パスで get_node() を使用することはできません。』をヒントに、change_level
を呼び出すシグナルとして tree_exited
以外に相応しいものがないのか探した。
すると、すぐ下に tree_exiting
なるシグナルがあった!
早速修正してみる。(上のボツ案で追加した2行は削除しておく。)
func add_level():
level = load("res://Levels/Level" + str(current_level) + ".tscn").instance()
# 旧:level.connect("tree_exited", self, "change_level")
level.connect("tree_exiting", self, "change_level") # 変更箇所
add_child(level)
player = level.get_node("Player")
player.connect("player_damaged", self, "_on_Player_player_damaged")
player.connect("item_hit", self, "_on_Player_item_hit")
表題のエラーは消えたが、以下のエラーが発生。
add_child: Parent node is busy setting up children, add_node() failed. Consider using call_deferred("add_child", child) instead.
add_child: 親ノードが子供の設定に追われているため、add_node()は失敗しました。代わりにcall_deferred("add_child", child)を使用することを検討してください。
「call_deferred godot」等でググった後『うん、なんとなくわかりました』と納得した上で、エラーメッセージの通り以下の修正を加えた。
func add_level():
level = load("res://Levels/Level" + str(current_level) + ".tscn").instance()
level.connect("tree_exiting", self, "change_level")
# 旧: add_child(level)
call_deferred("add_child", level) # 変更箇所
player = level.get_node("Player")
player.connect("player_damaged", self, "_on_Player_player_damaged")
player.connect("item_hit", self, "_on_Player_item_hit")
エラーが消えた!!
最後に
本当はボツ案に記した内容の前に、別の方法を試しました。
お手本の方法(Restart時にGame.gbを破棄して読み直す方法)を採用しない形を考えて作業を進めてみたのです。できないことは無さそうでしたが、かなりゴチャつきそうだったので、素直にお手本の方法のままエラー除去する方法を探すことにしたのです。
is_instance_valid
を見つけて『これでいける!』と思ったところにエラー吐かれてガックリしましたが、諦めなければ何とかなるものです。
こんなことで一苦労しているのは自分だけでしょうか。
地道にがんばります。