1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Godot Engine エラー "get_tree: Condition "!data.tree" is true. Returned: nullptr" の対処について

Posted at

はじめに

PeanutsCodeさんのプラットフォーマー制作でGodotを学習中。
前回がPart8、今回はPart9。連続で何かしら発生してます。

環境

  • Windows版 Godot Engine Ver.3.5(stable)
  • GDScript

現象

プラットフォーマー制作Part9において、ゲームオーバー画面から、Restart / Quit を実行すると下記エラーが発生。実行は続く。

error
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()

		# 中略

エラー。。

error
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")

表題のエラーは消えたが、以下のエラーが発生。

error
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」等でググった後『うん、なんとなくわかりました:relaxed:』と納得した上で、エラーメッセージの通り以下の修正を加えた。

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 を見つけて『これでいける!』と思ったところにエラー吐かれてガックリしましたが、諦めなければ何とかなるものです。

こんなことで一苦労しているのは自分だけでしょうか。
地道にがんばります。:walking_tone1:

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?