Godot 4のコンポーネント指向開発シリーズ、今回は敵AIの基礎となる**「TargetFollower (ターゲット追尾)」**です。
ゾンビ、追跡ミサイル、ペットなど、「何かを追いかける動き」を実装する際、毎回移動コードを書くのは大変です。このコンポーネントを使えば、アタッチするだけで勝手にターゲットを追いかけるオブジェクトを作成できます。
このコンポーネントは、シーン内から「特定のグループ(例: player)」に所属するノードを自動で探し出し、その場所に向かって親ノードを移動させます。
1. コンポーネントのコード (Full Code)
以下のコードをコピーして、TargetFollower.gd という名前で保存してください。
class_name TargetFollower
extends Node
## 指定したグループの対象を自動で追尾するコンポーネント
## 親ノードは CharacterBody2D を想定しています。
# --- 設定パラメータ ---
@export_group("AI Settings")
@export var target_group: String = "player" ## 追尾対象が所属しているグループ名
@export var speed: float = 100.0 ## 移動速度
@export var stop_distance: float = 20.0 ## ターゲットの手前で止まる距離(重なり防止)
# --- 内部変数 ---
var _parent: CharacterBody2D
var _target: Node2D = null
func _ready() -> void:
# 親ノードの取得
_parent = get_parent() as CharacterBody2D
if not _parent:
push_error("TargetFollower: 親が CharacterBody2D ではありません。")
set_physics_process(false)
return
# ターゲットの検索 (シーン読み込み完了後に行うため少し待つ)
await get_tree().process_frame
_find_target()
func _physics_process(_delta: float) -> void:
# ターゲットがいなければ何もしない(または再検索する)
if not is_instance_valid(_target):
return
# ターゲットへのベクトル(方向と距離)を計算
var direction_vector = _target.global_position - _parent.global_position
var distance = direction_vector.length()
# 指定距離より遠ければ移動する
if distance > stop_distance:
# 正規化(長さを1にする)して速度を掛ける
_parent.velocity = direction_vector.normalized() * speed
_parent.move_and_slide()
# (オプション) 進行方向を向く場合は以下を有効化
# _parent.look_at(_target.global_position)
else:
# 近すぎる場合は止まる
_parent.velocity = Vector2.ZERO
func _find_target() -> void:
# 指定したグループに所属するノードのリストを取得
var targets = get_tree().get_nodes_in_group(target_group)
if targets.size() > 0:
# とりあえず最初の1人(プレイヤー)をターゲットにする
_target = targets[0] as Node2D
else:
# 見つからなかった場合(プレイヤーが死んでいる等)
# print_debug("TargetFollower: ターゲットが見つかりません")
pass
2. 使い方チュートリアル
このコンポーネントを動かすには、「追いかける側(敵)」と「追いかけられる側(プレイヤー)」の準備が必要です。Godotの便利な機能**「グループ」**を使用します。
手順①:プレイヤー(ターゲット)の準備
まず、追いかけられる対象を作ります。
- プレイヤーのシーン(またはノード)を開きます。
- ノードタブの 「グループ (Groups)」 を選択します。
playerと入力して追加ボタンを押します。- これで、このノードに「player」というタグが付きました。
手順②:敵(親ノード)の作成
- 新しいシーンを作成し、ルートノードを
CharacterBody2Dにします(名前はEnemyなど)。 CollisionShape2DとSprite2Dを追加して、敵の見た目を作ります。
手順③:コンポーネントのアタッチ
Enemyノードの子としてNodeを追加し、名前をTargetFollowerにします。- 先ほどのスクリプト
TargetFollower.gdをアタッチします。 - インスペクター設定を確認します:
- Target Group:
player(手順1で付けた名前と同じか確認) - Speed:
100(適当な速さ)
- Target Group:
シーン構成図:
Enemy (CharacterBody2D)
├── Sprite2D (敵の画像)
├── CollisionShape2D
└── TargetFollower (Node) <-- これが自動操縦エンジンになります
手順④:実行
メインシーンに「プレイヤー」と「敵」の両方を配置して実行してください。
敵が一直線にプレイヤーに向かって動き出し、近づくとピタリと止まれば成功です!
3. このコンポーネントの活用・発展
複数の敵を一瞬で作る
この Enemy シーンを保存しておけば、メインシーンに10体でも20体でも配置するだけで、全員がプレイヤーを追いかけてくる「大量発生イベント」がすぐに作れます。コードをコピー&ペーストする必要はありません。
壁を避けるには? (NavigationAgent2D)
今回のコードは「壁があっても無視して直進(または壁に引っかかり続ける)」という単純なものです。
もし迷路のようなステージで壁を避けて追いかけさせたい場合は、Godot標準の NavigationAgent2D ノードと組み合わせるのが正解です。
このコンポーネントを改造して、NavigationAgent2D を使うようにすれば、「賢い追尾AI」にアップグレードできます。
ターゲットの切り替え
_find_target() のロジックを変えれば、挙動を変化させられます。
- 一番近い敵を狙う:
targets配列の中身をループして、距離が最も近いノードを_targetに設定する。 - ランダムに狙う:
targets.pick_random()を使用する。
このように、「誰を狙うか」のロジックと**「どう動くか」のロジック**をこのコンポーネント内に閉じ込めておけるのがメリットです。
