「画面上の敵全員を一斉に怯ませたい」「プレイヤーの攻撃が当たったのが敵なのか、壊せる箱なのか、アイテムなのかを見分けたい」——ゲームを作っていると、こうした「役割でまとめて扱いたい」場面が次々に出てきます。
これをノードの親子関係や if body.name == "Slime" のような名前判定でこなそうとすると 、敵を1種類増やすたびにコードを直す羽目になり、すぐに破綻します。そこで役立つのがGodotの グループ(Groups) 機能です。ノードに 役割のタグ を貼っておけば、種類やクラスを気にせず「タグでまとめて」判定・命令できます。
この記事でわかること
- グループ =シーン階層から独立した「役割のタグ付け」システム
add_to_group()での登録と、is_in_group()での 柔軟な判定call_group()による グループへの一斉命令- メタデータ・
class_name・ダックタイピングとの 使い分け
グループとは?役割の「タグ付け」システム
グループは、シーンツリーの階層やノードの種類とは 無関係に、ノードへ仮想的な 「タグ」 を貼るシステムです。CharacterBody2D に「enemies」、Area2D に「collectible_items」——といった具合に、クラスが違っても同じタグでまとめられます。

ポイントは、この分類が ツリー構造を横断する ことです。ツリーのどこに置かれていても、種類が何であっても、「enemies」タグさえ貼れば同じ仲間として扱えます。グループの利点は3つです。
- 役割で分類できる :親子関係に縛られず、「敵」「拾えるもの」といった意味のまとまりで括れる
- 一括操作できる :「enemies」全員を取得してまとめて命令、が簡単に書ける
- 疎結合になる :ノード同士が直接参照し合わなくても、タグという共通の目印で連携できる
1つのノードは 複数のグループ に入れます。敵を「enemies」かつ「rangers(遠距離)」に入れておけば、「全敵」にも「遠距離の敵だけ」にも絞り込めます。
グループに追加する2つの方法
グループへの追加は、 エディタ と コード の2通りです。配置済みの静的なノードはエディタで、実行中に生成されるノードはコードで、と使い分けます。

エディタで追加(静的なノード向け) :シーンツリーでノードを選び、インスペクタ隣の「ノード」タブ →「グループ」を開き、グループ名(例: enemies)を入力して「追加」を押します。
コードで追加(動的なノード向け) :弾やエフェクトのように実行中に生成されるノードは、add_to_group() で登録します。
# bullet.gd
func _ready() -> void:
add_to_group("player_bullets") # 生成時に自分をグループへ登録
func _on_hit_target() -> void:
remove_from_group("player_bullets") # 不要になったら抜ける(任意)
queue_free()
is_in_groupで「相手が何者か」を判定する
グループがもっとも輝くのが、 衝突相手の判定 です。is_in_group() を使うと、「ぶつかった相手が敵か、壊せる箱か」を 具体的なクラスを知らずに 見分けられます。

# player_attack_area.gd(Area2D:プレイヤーの剣の当たり判定)
func _on_body_entered(body: Node) -> void:
# 相手が "enemies" タグを持ち、take_damage を実装しているか
if body.is_in_group("enemies") and body.has_method("take_damage"):
body.take_damage(attack_power)
# 壊せるオブジェクトなら壊す
elif body.is_in_group("destructible_objects") and body.has_method("destroy"):
body.destroy()
このコードの美点は、PlayerAttackArea が攻撃対象の具体的なクラス(Slime や Goblin)を 一切知らない ことです。新しい敵を追加しても、このスクリ プトは無修正でよく、 新しいノードを「enemies」グループに入れるだけ で攻撃が通るようになります。is_in_group()(タグ確認)と has_method()(振る舞い確認)を組み合わせると、より安全です。
実践:画面全体の敵に一斉命令する
ボムアイテムで全画面の敵を怯ませる、警報で全警備員を警戒させる、ターン制で敵全体に状態異常を配る——「特定の役割のノード全員に、同じ命令を一斉に送りたい」場面は、ジャンルを問わず頻出します。get_tree().call_group() を使えば、 相手が何体いてどこにいるかを知らなくても 、グループ全員のメソッドを一度に呼べます。

警報システムを例に組んでみましょう。命令を送る側は、call_group() を1回呼ぶだけです。
# alarm_system.gd
func _on_alarm_triggered() -> void:
# "guards" グループ全員の enter_alert_mode を、引数つきで一斉に呼ぶ
get_tree().call_group("guards", "enter_alert_mode", get_player_last_position())
命令を受ける側(警備員)は、グループに入っておき、呼ばれるメソッドを用意しておくだけです。
# guard.gd (CharacterBody2D)
func _ready() -> void:
add_to_group("guards") # 生成時にguardsへ登録
func enter_alert_mode(target_position: Vector2) -> void:
state = State.ALERT # 状態を警戒へ
nav_agent.target_position = target_position # 最後に見た位置へ向かう
ポイントは2つです。
- 送る側は「何体いるか」を知らなくてよい :
AlarmSystemはシーン内の警備員の数も位置も気にしません。増えても減っても、call_group()の1行は変わらないので、 敵の増減に強い 設計になります。 - メソッドが無いノードは黙って無視される :
call_group()は、対象がそのメソッドを持たなくても エラーにならず何もしません 。逆に言えば呼び忘れに気づきにくいので、グループ内のノードが確実に該当メソッドを持つよう揃えるか、has_method()で確認します。
警備員一人ひとりの「警戒→追跡」の賢い動きは ステートマシンで管理するAIとプレイヤーの状態、目標地点への移動は NavigationAgent2Dによるパスファインディング の領域です。グループは「全員に号令をかける」役に徹し、個々の頭脳は各ノードに任せるときれいに分業できます。
よくある間違いとベストプラクティ ス
| よくある間違い | ベストプラクティス |
|---|---|
_process 内で get_nodes_in_group() を呼ぶ | _ready() でリストをキャッシュするか、call_group()・シグナルを使う。毎フレームのシーン全探索は高コスト |
| あらゆる判定をグループで済ませる | 役割は動的な分類向き。静的な型判定は class_name、値の付与はメタデータ、と使い分ける |
| グループ名を文字列で直書きする | const ENEMY_GROUP := "enemies" のように定数化し、タイプミスや変更漏れを防ぐ |
特に グループ名の直書き は地味に効いてきます。"enemies" を何十箇所にも書くと、綴りミス1つでその判定だけ静かに動かなくなります。定数やAutoloadにまとめておけば、名前の変更も1箇所で済みます。
他の手法との使い分け
グループは万能ではありません。目的によっては、別の仕組みの方がシンプルで速いこともあります。

| 手法 | 得意なこと | 使いどころ |
|---|---|---|
| グループ | 役割でまとめて検索・一括命令 | 「全敵」「拾えるもの」など動的な役割 |
メタデータ set_meta/get_meta | ノードに静的な値を付与 | item_id など個体ごとの固定値 |
class_name | 型で厳密に判定(is Enemy) | 特定クラスのインスタンスを扱う |
ダックタイピング has_method | 型を知らず振る舞いで分岐 | 「take_damage を持つなら」で処理する |
これらは競合ではなく 相補的 です。実際、先ほどの当たり判定でも「グループで役割を確認しつつ has_method() で振る舞いも確認」と組み合わせていました。役割はグループ、型は class_name、能力は has_method、値はメタデータ——と、それぞれの得意分野で使い分けるのがきれいな設計です。
なお、物理的な「誰と誰がぶつかるか」の制御はグループではなく Collision LayersとMasks の担当です。グループは衝突「後」のロジック判定、レイヤーは衝突「そのもの」のフィルタ、と役割が分かれています。
おまけ:先に知っておくと良いこと
- シグナルとの相性 :グループは「こちらから全員へ号令」に向きます。逆に「何かが起きたことを各所へ知らせる」なら シグナル が適します。号令はグループ、通知はシグナル、と覚えると迷いません。
- グループ内の順序は保証されない :
get_nodes_in_group()の並び順に依存した処理は書かないのが安全です。順序が要るなら自前で並べ替えます。 call_groupにはフラグ版もある :call_group_flags()を使うと、呼び出しを遅延させる(そのフレームの最後にまとめて実行)などの制御ができます。大量ノードへの一斉命令で役立つ場面があります。
まとめ
- グループ はシーン階層から独立した「役割のタグ付け」。クラスが違っても同じタグでまとめられる
- 追加はエディタ(静的)と
add_to_group()(動的)の2通り is_in_group()で 相手の役割を判定 し、具体的なクラスを知らずに処理を分岐できるget_tree().call_group()で グループ全員に一斉命令 。送る側は数も位置も知らなくてよいget_nodes_in_group()の毎フレーム呼び出しは避け、キャッシュやcall_group()を使う- メタデータ・
class_name・has_methodと 適材適所 で組み合わせる
まずは敵を「enemies」グループに入れ、プレイヤーの攻撃で is_in_group("enemies") を判定するところから試してみてください。「クラスを増やしてもコードが増えない」感覚が、グループの本当のうれしさです。
さらに学ぶために
- シグナルによるノード間の連携 ——「通知」はシグナル、「号令」はグループ
- ステートマシンで管理するAIとプレイヤーの状態 ——号令を受けた各ノードの頭脳
- Collision LayersとMasks ——物理的な衝突フィルタとの違い
- Godot公式ドキュメント:Groups ——グループの一次情報