INDIE INDEX

Claude Codeが書いたGodotのシーンとノードの読み方【AIでゲーム開発】

公開 2026-09-24更新 2026-09-24Claude Code

Claude Code が書いた Godot の .tscn では、[node で始まる1行が1つのノードで、名前・種類・親・グループはその行に、付いているスクリプトはすぐ下の script の行にありました。シグナルのつながりは .gd の connect の行にありました。この試しでは、グループが見出しの行の外に書かれていてスコアが増えず、1回の直しで5枚目に CLEAR が出るようになりました。

このページの目次
  1. Claude Code に頼んだ文
  2. できたファイルと、Claude Code の説明
  3. .tscn の中でノードを見つける
  4. 別のシーンを置いたノードを読む
  5. .gd の中でノードとシグナルを見つける
  6. 説明と実物を1つずつ比べる
  7. Godot を画面なしで動かして確かめる
  8. Claude Code に直しを頼んだ文
  9. 直したあとの結果
  10. 情報源

Claude Code に頼んだ文

Godot のエディタを開かずに、Claude Code にファイルを直接書かせました。Godot では、ゲームはシーンに分かれ、1つのシーンはノードの木でできています。できたシーンは、別のシーンの中に置くことができます。Claude Code は、プロジェクトのファイルを読み、ファイルを書き換え、コマンドを動かすツールです。頼んだ文はそのまま次のとおりです(作業フォルダの場所だけが手元のものです)。

Claude CodeにGodotのコイン集めのゲームを頼んだ文

作業フォルダは D:\Claude_Game_Site\drafts\W-142-A\godot-scene-nodes.play\ だけです。このフォルダの外は読まない・書かないでください。

Godot 4 で、2D の小さなゲームのプロジェクトを作ってください。 中身は簡単でいいです:左右キーで動いて上キーでジャンプするプレイヤーが、画面に置いたコイン5枚を集めます。コインに触れるとコインが消えてスコアが1増え、5枚集めたら画面に「CLEAR」と出ます。 シーンは、メインのシーン・プレイヤー・コインを別々のファイルに分けてください。コインを取ったことは、コインからシグナルで知らせてください。 Godot のエディタは開けないので、ファイル(project.godot・.tscn・.gd)を直接書いてください。

できたら、作ったファイルの一覧と、それぞれのシーンにどのノードがあって、どのスクリプトが付いているかを短く返してください。

Claude Code が作り終えるまでの時間は143秒でした。

できたファイルと、Claude Code の説明

できたのは次の7つのファイルです。

  1. project.godot:最初に動くシーンが scenes/Main.tscn になっている
  2. scenes/Main.tscn:メインのシーン
  3. scenes/Player.tscn:プレイヤーのシーン
  4. scenes/Coin.tscn:コインのシーン
  5. scripts/Main.gd:スコアを数えて、5枚で CLEAR を出す
  6. scripts/Player.gd:左右の移動とジャンプ
  7. scripts/Coin.gd:プレイヤーと重なったらシグナルを出して消える

Claude Code の返事では、Main.tscn の一番上のノード(ルート)は Node2D で Main.gd が付き、その下に Floor・Player・Coin1〜5("coins" グループ)・CanvasLayer があり、CanvasLayer の下に ScoreLabel と ClearLabel がある、と説明されました。Player.tscn のルートは CharacterBody2D、Coin.tscn のルートは Area2D で、コインは collected というシグナルを出してから消える、という説明でした。

.tscn の中でノードを見つける

.tscn はテキストのファイルで、角かっこの見出しの行と、その下の「名前 = 値」の行でできています。見出しの行には、ファイルの外の部品・ファイルの中の部品・ノード・シグナルのつながりの4種類があります。Coin.tscn は次のとおりでした(ファイルの中身そのまま)。

[gd_scene load_steps=2 format=3]

[ext_resource type="Script" path="res://scripts/Coin.gd" id="1"]

[sub_resource type="CircleShape2D" id="CircleShape2D_coin"]
radius = 12.0

[node name="Coin" type="Area2D"]
script = ExtResource("1")

[node name="ColorRect" type="ColorRect" parent="."]
offset_left = -12.0
offset_top = -12.0
offset_right = 12.0
offset_bottom = 12.0
color = Color(1, 0.85, 0.1, 1)

[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_coin")
  1. ノードは、[node で始まる1行が1つです。name= が名前、type= が種類です。
  2. parent= が親です。最初の [node の行(ルート)には parent がありません。ルートのすぐ下の子は parent="." です。Main.tscn では、Floor の下の ColorRect が parent="Floor"、ScoreLabel が parent="CanvasLayer" でした。
  3. 付いているスクリプトは、[node の行のすぐ下の script の行です。かっこの中の "1" は、ファイルの頭にあるファイルの外の部品の行のうち id="1" のものを指します。その行の path= が res://scripts/Coin.gd です。
  4. 当たりの形のように、ファイルの中で作る部品は、ノードより上の行にあり、ノードの側から SubResource の行で指されます。Coin.tscn では、CollisionShape2D が半径12の CircleShape2D を指していました。

別のシーンを置いたノードを読む

Main.tscn の Player と Coin1〜5 は、別のシーンを置いたノードです。[node の行に type= が無く、instance= がありました。

[ext_resource type="PackedScene" path="res://scenes/Player.tscn" id="2"]
[ext_resource type="PackedScene" path="res://scenes/Coin.tscn" id="3"]

[node name="Player" parent="." instance=ExtResource("2")]
position = Vector2(100, 550)

Coin1〜5 の instance= のかっこの中は "3" で、頭の行の id="3" の res://scenes/Coin.tscn を指します。このため、Coin1 の種類(Area2D)と付いているスクリプト(Coin.gd)は Main.tscn の中には無く、Coin.tscn の [node name="Coin" type="Area2D"] の行と、その下の script の行にあります。Main.tscn の Coin1〜5 の行の下には、置く場所(position)の行がありました。

.gd の中でノードとシグナルを見つける

.gd は GDScript のファイルです。3つとも、1行目の extends が、そのスクリプトが付くノードの種類と同じでした(Coin.gd は Area2D、Player.gd は CharacterBody2D、Main.gd は Node2D)。Coin.gd は次のとおりでした(ファイルの中身そのまま)。

extends Area2D

signal collected

func _ready() -> void:
	body_entered.connect(_on_body_entered)

func _on_body_entered(body: Node2D) -> void:
	if body.is_in_group("player"):
		collected.emit()
		queue_free()
  1. signal collected の行が、コインが出すシグナルの名前です。
  2. ノードが動き始めたときに呼ばれる関数の中で、ほかの物体が重なったときの知らせを、下の関数につないでいます。
  3. 重なった相手が "player" グループなら、collected のシグナルを出してから、コインを消します。

Main.gd の7〜14行目は次のとおりでした(ファイルの中身そのまま)。

@onready var score_label: Label = $CanvasLayer/ScoreLabel
@onready var clear_label: Label = $CanvasLayer/ClearLabel

func _ready() -> void:
	clear_label.visible = false
	_update_score_label()
	for coin in get_tree().get_nodes_in_group("coins"):
		coin.collected.connect(_on_coin_collected)
  1. $ のあとの CanvasLayer/ScoreLabel は、Main から見て CanvasLayer の下の ScoreLabel を指す道です。.tscn の parent= の並びと同じです。
  2. 動き始めたときに "coins" グループのノードを集め、それぞれの collected を、スコアを数える関数につないでいます。スコアを数える関数は、スコアを1増やし、5以上で ClearLabel を見えるようにします。
  3. 3つの .tscn には [connection で始まる行が1行もありませんでした。このプロジェクトでは、シグナルのつながりはすべて .gd の connect の行で作られています。

説明と実物を1つずつ比べる

Claude Code の返事の説明を、.tscn と .gd の中身と1つずつ比べました。

各シーンのノードの名前・種類・親子と、付いているスクリプト(Main.tscn の Main に Main.gd、Player.tscn の Player に Player.gd、Coin.tscn の Coin に Coin.gd)と、シグナル(Coin.gd の signal collected)は、返事のとおりでした。グループは次のとおりでした。

  1. "player" グループ:Player.tscn では、[node name="Player" type="CharacterBody2D" groups=["player"]] と、[node の行の中にありました。
  2. "coins" グループ:返事と違っていました。Main.tscn では、groups=["coins"] が [node の行の中ではなく、その下の行にありました。

groups は、[node の見出しの行の中に書く項目の1つです。見出しの行の下の行は、そのノードのプロパティ(position など)の値です。

Godot を画面なしで動かして確かめる

Godot 4.7.2 を画面なしで動かしました。プロジェクトのファイルは書き換えず、試しの台本はプロジェクトの外に置きました。

  1. プロジェクトを読み込んで1回だけ回して終える形で動かすと、出たのは Godot の版の1行だけで、エラーも警告もありませんでした。
  2. 台本で Main.tscn を読み込み、読み込んだあとの様子を書き出しました。"coins" グループのノードは0個、"player" グループは1個でした。Coin1〜5 の collected につながっている先は0本でした。
  3. 台本から上の操作を押すと、プレイヤーはジャンプして床に戻りました。そのあと右の操作を押し続けると、コインは5枚とも消えましたが、スコアは「Score: 0」のままで、CLEAR は出ませんでした。

"coins" グループが空なので、Main.gd がグループから1つもコインを受け取れず、collected がどこにもつながっていない状態でした。本物のキーボードの矢印キーを押したときの動きは、この試しでは確かめきれませんでした。

Claude Code に直しを頼んだ文

起きたこと・起こし方・調べて分かったこと・望む動きを書いて、別の Claude Code に1回渡しました。渡した文はそのまま次のとおりです。

Claude Codeに直しを頼んだ文

作業フォルダは D:\Claude_Game_Site\drafts\W-142-A\godot-scene-nodes.play\ だけです。このフォルダの外は読まない・書かないでください。
前に作ってもらったコイン集めのプロジェクトで、次のことが起きました。
・起きたこと:プレイヤーがコインに触れるとコインは消えますが、スコアは「Score: 0」のままで、5枚取っても「CLEAR」が出ません。
・起こし方:Godot 4.7.2 を画面なしで動かし、Main.tscn を読み込んで右キーを押し続けたまま、5枚のコインの上を通らせました。読み込みのときにエラーは出ませんでした。
・調べて分かったこと:読み込んだあとで "coins" グループに入っているノードは0個でした。
・望む動き:コインに触れるたびにスコアが1増え、5枚で「CLEAR」が出ること。
直したら、どのファイルの何行目をどう変えたかと、.tscn の中でノードの名前・種類・親・グループ・スクリプトがそれぞれどこに書かれているかを、Main.tscn の Coin1 を例に短く返してください。

Claude Code が直し終えるまでの時間は51秒でした。

直したあとの結果

Claude Code は、Main.tscn の Coin1〜Coin5 の5か所で、groups=["coins"] を [node の行の中に移しました。直したあとの Coin1 は次のとおりです。

[node name="Coin1" parent="." groups=["coins"] instance=ExtResource("3")]
position = Vector2(250, 560)

直したあとを、Godot を画面なしで動かして数え直しました。

  1. 読み込みでは、エラーも警告も出ませんでした。
  2. "coins" グループのノードは5個になり、Coin1〜5 の collected はそれぞれ1本ずつ、スコアを数える関数につながっていました。
  3. 台本から右の操作を押し続けると、コインに触れるたびにスコアが1ずつ増えて「Score: 5」になり、CLEAR が見えるようになりました。

直したあとのゲームを窓のある Godot で動かし、コインを5枚取った画面。左上に Score: 5、真ん中に CLEAR の文字が出ている

直す前に groups が次の行にあったときに、エラーも警告も出ずにグループに入らなかったことは、前の節で動かして見たとおりです。Claude Code は、その理由を「見出しの行の外に書くと groups という名前のプロパティへの代入として扱われ、Area2D にも Coin.gd にもそのプロパティが無いので、黙って無視された」と説明しました。この試しで確かめたのは、読み込んだ Coin1 のプロパティの一覧に groups という名前が無いことまでです。

情報源

Claude Code のほかのページ

このページに出た言葉