<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AI／振る舞い on Godot 4 レシピ</title><link>https://kamera25.github.io/godot_recipes/4.x/ja/ai/index.html</link><description>Recent content in AI／振る舞い on Godot 4 レシピ</description><generator>Hugo -- gohugo.io</generator><language>ja</language><atom:link href="https://kamera25.github.io/godot_recipes/4.x/ja/ai/index.xml" rel="self" type="application/rss+xml"/><item><title>プレイヤーを追いかける</title><link>https://kamera25.github.io/godot_recipes/4.x/ja/ai/chasing/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kamera25.github.io/godot_recipes/4.x/ja/ai/chasing/index.html</guid><description>&lt;h2 id="課題"&gt;課題&lt;/h2&gt;
&lt;p&gt;プレイヤーを追いかける敵が欲しい。&lt;/p&gt;
&lt;h2 id="解決策"&gt;解決策&lt;/h2&gt;
&lt;p&gt;敵をプレイヤー追跡モードに移行させる最初のステップは、敵が移動する必要のある方向を決定することです。ベクトル &lt;strong&gt;A&lt;/strong&gt; から &lt;strong&gt;B&lt;/strong&gt; への方向を求めるには、以下のように計算します。&lt;strong&gt;B&lt;/strong&gt; - &lt;strong&gt;A&lt;/strong&gt;。この結果を正規化すれば、方向ベクトルが得られます。&lt;/p&gt;
&lt;p&gt;このアプローチは非常にシンプルです。毎フレーム、敵の速度ベクトルをプレイヤー方向へ向くように設定します。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;player&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;position &lt;span style="color:#81a1c1"&gt;-&lt;/span&gt; position&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;normalized&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; speed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Godotの&lt;code&gt;Vector2&lt;/code&gt;オブジェクトには、この処理を補助する組み込み機能があります。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; position&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;direction_to&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;player&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;position&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; speed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;しかし、これでは敵がプレイヤーから遠距離にいても追跡できてしまいます。これを修正するには、敵に &lt;i class="gd-Area2D"&gt;&lt;/i&gt;&lt;code&gt;Area2D&lt;/code&gt; を追加し、この「検出範囲」内にプレイヤーが入った場合にのみ追跡するようにします。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-64d0f8d759d43d7b0639b0872bd6f166" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/chase_01.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-64d0f8d759d43d7b0639b0872bd6f166"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/chase_01.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以下にサンプルコードを示します。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;extends&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;CharacterBody2D&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; run_speed &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;25&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; player &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_physics_process&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;delta&lt;span style="color:#eceff4"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Vector2&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;ZERO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; player&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; position&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;direction_to&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;player&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;position&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; run_speed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#88c0d0"&gt;move_and_slide&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_on_DetectRadius_body_entered&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;body&lt;span style="color:#eceff4"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; player &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; body
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_on_DetectRadius_body_exited&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;body&lt;span style="color:#eceff4"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; player &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;i class="gd-Area2D"&gt;&lt;/i&gt;&lt;code&gt;Area2D&lt;/code&gt;からの&lt;code&gt;body_entered&lt;/code&gt;シグナルと&lt;code&gt;body_exited&lt;/code&gt;シグナルを接続しました。これで、敵が範囲内にいるか判別できるようになりました。&lt;/p&gt;
&lt;p&gt;上記の説明では、プレイヤーだけが出入りすることを想定しています。これは、適切な衝突レイヤーとマスクを設定することで実現できます。&lt;/p&gt;
&lt;p&gt;&lt;video controls src="https://kamera25.github.io/godot_recipes/4.x/img/chase_02.webm"&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;この手法は他の種類のゲームにも応用できます。重要なのは、敵からプレイヤーへの方向ベクトルを求めることです。&lt;/p&gt;
&lt;p&gt;たとえば、ゲームがサイドスクロール形式であったり、移動に制限がある場合は、得られたベクトルの &lt;code&gt;x&lt;/code&gt; 成分のみを使用して移動を判定できます。&lt;/p&gt;
&lt;h3 id="制約事項"&gt;制約事項&lt;/h3&gt;
&lt;p&gt;この方法による移動は非常に単純化されています。壁などの障害物を回避したり、プレイヤーに近づきすぎて停止したりすることはありません。&lt;/p&gt;
&lt;p&gt;敵がプレイヤーに接近した際の対処はゲームデザインによって異なります。以下の選択肢が考えられます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2つ目の小さいエリアを追加し、そこで敵を足止めして攻撃させるか&lt;/li&gt;
&lt;li&gt;接触時にプレイヤーを吹き飛ばすノックバック効果を実装するか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;さらに顕著な問題は、動きの速い敵キャラクターで発生します。プレイヤーが移動すると、このテクニックを使用する敵は瞬時に進行方向を変えます。より自然な動きを実現するためには、ステアリング挙動を使用することをオススメします。&lt;/p&gt;
&lt;p&gt;より高度な動作については、本書の他のレシピを参照してください。&lt;/p&gt;
&lt;h2 id="関連レシピ"&gt;関連レシピ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kamera25.github.io/godot_recipes/4.x/ja/2d/topdown_movement/#option-1-8-way-movement"&gt;見下ろし型のキャラクター移動&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kamera25.github.io/godot_recipes/4.x/ja/ai/homing_missile/"&gt;追跡ミサイル&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>パスを追従する</title><link>https://kamera25.github.io/godot_recipes/4.x/ja/ai/path_follow/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kamera25.github.io/godot_recipes/4.x/ja/ai/path_follow/index.html</guid><description>&lt;div class="box notices cstyle tips"&gt;
&lt;div class="box-label"&gt;ℹ️ 留意事項&lt;/div&gt;
&lt;div class="box-content"&gt;
&lt;p&gt;この記事は Godot 3から Godot 4 へ内容の書き換え中です。
Godot4では存在しない変数、関数が含まれている場合があります。もしその場合はリポジトリの&lt;a href="https://github.com/kamera25/godot_recipes/issues" target="_blank"&gt;Issues&lt;/a&gt;までご報告ください。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="課題"&gt;課題&lt;/h2&gt;
&lt;p&gt;以下のような事前に定義された経路を移動するキャラクターが必要です。警備員が巡回する場面や、車両が道路を走るシーンなど。&lt;/p&gt;
&lt;h2 id="解決策"&gt;解決策&lt;/h2&gt;
&lt;p&gt;この問題に対処する方法は複数あります。ここでは一例として、エディター内でパスを描画するための便利な方法として、Godotの&lt;i class="gd-Path2D"&gt;&lt;/i&gt;&lt;code&gt;Path2D&lt;/code&gt;ノード（3Dの場合は&lt;i class="gd-Path3D"&gt;&lt;/i&gt; &lt;code&gt;Path&lt;/code&gt;）を使用します。&lt;/p&gt;
&lt;p&gt;以下の方法ができます。メインシーン、マップ、またはその他適切な場所に&lt;i class="gd-Path2D"&gt;&lt;/i&gt;&lt;code&gt;Path2D&lt;/code&gt;を子要素として追加できます。ただし、巡回エンティティの子要素に設定しないようご注意ください - そうすると経路がプレイヤーと一緒に移動してしまいます！&lt;/p&gt;
&lt;h3 id="経路の描画"&gt;経路の描画&lt;/h3&gt;
&lt;p&gt;&lt;i class="gd-Path2D"&gt;&lt;/i&gt;&lt;code&gt;Path2D&lt;/code&gt;ノードを追加すると、ビューポート上部に新しいボタンが表示されます。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-16488b2d9f37379c81f95f1181394152" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/path2d_buttons.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-16488b2d9f37379c81f95f1181394152"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/path2d_buttons.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;「ポイント追加」ボタンを選択してクリックし、追加を開始します。閉じた曲線を作成したい場合は、「曲線を閉じる」ボタンをクリックすると最後の点が最初の点に接続されます。&lt;/p&gt;
&lt;p&gt;「制御点」モードを使用して、線の「曲線度」を調整できます。&lt;/p&gt;
&lt;h3 id="経路に沿った移動"&gt;経路に沿った移動&lt;/h3&gt;
&lt;p&gt;以下のタグを使用して経路に沿って自動移動させることができます。&lt;i class="gd-PathFollow2D"&gt;&lt;/i&gt;&lt;code&gt;PathFollow2D&lt;/code&gt;。ただし、キャラクターボディを使用している場合、この方法は衝突判定に問題を引き起こす可能性があります。これはボディの移動メソッドを利用していないためです。このため、代わりに経路上の各点を「目標」として設定し、ボディがその方向へ移動するようにします。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;extends&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;CharacterBody2D&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; move_speed &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d08770"&gt;@export&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; patrol_path&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;NodePath&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; patrol_points
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; patrol_index &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Vector2&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;ZERO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_ready&lt;/span&gt;&lt;span style="color:#eceff4"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; patrol_path&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; patrol_points &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;get_node&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;patrol_path&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;curve&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;get_baked_points&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;patrol_path&lt;/code&gt;をエクスポートすることで、インスペクター内で直接パスノードを割り当てることができます。その後、そのノードが割り当てられていれば、&lt;code&gt;_ready()&lt;/code&gt;関数内でラインを構成するポイント情報を取得可能です。&lt;/p&gt;
&lt;p&gt;次のステップとして、現在パス上で選択されている点を移動先として使用できます。十分に近づけると、曲線の次のポイントに移動し、&lt;code&gt;wrapi()&lt;/code&gt; 関数を使用して終点に到達したら最初のポイントに戻るループ処理を行います。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_physics_process&lt;/span&gt;&lt;span style="color:#eceff4"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;!&lt;/span&gt;patrol_path&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; target &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; patrol_points&lt;span style="color:#eceff4"&gt;[&lt;/span&gt;patrol_index&lt;span style="color:#eceff4"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; position&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;distance_to&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;target&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#b48ead"&gt;1&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; patrol_index &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;wrapi&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;patrol_index &lt;span style="color:#81a1c1"&gt;+&lt;/span&gt; &lt;span style="color:#b48ead"&gt;1&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; patrol_points&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;size&lt;/span&gt;&lt;span style="color:#eceff4"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; patrol_points&lt;span style="color:#eceff4"&gt;[&lt;/span&gt;patrol_index&lt;span style="color:#eceff4"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;target &lt;span style="color:#81a1c1"&gt;-&lt;/span&gt; position&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;normalized&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; move_speed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;move_and_slide&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;velocity&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="関連レシピ"&gt;関連レシピ&lt;/h2&gt;</description></item><item><title>追跡ミサイル</title><link>https://kamera25.github.io/godot_recipes/4.x/ja/ai/homing_missile/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kamera25.github.io/godot_recipes/4.x/ja/ai/homing_missile/index.html</guid><description>&lt;h2 id="課題"&gt;課題&lt;/h2&gt;
&lt;p&gt;必要になるのが「追跡ミサイル」です。これは移動する標的を自動で追尾する砲弾です。&lt;/p&gt;
&lt;h2 id="解決策"&gt;解決策&lt;/h2&gt;
&lt;p&gt;この例では、プロジェクトイルとして &lt;i class="gd-Area2D"&gt;&lt;/i&gt;&lt;code&gt;Area2D&lt;/code&gt; ノードを使用します。エリアは通常、衝突検出が必要な弾丸に適しています。もし跳ね返る/反射するタイプの弾丸も必要であれば、&lt;code&gt;PhysicsBody&lt;/code&gt; 型のノードの方が適しているかもしれません。&lt;/p&gt;
&lt;p&gt;ミサイルのノード設定と動作原理は一般的な「単純な」弾丸と同様です。多数の異なる種類の弾丸を作成する場合、継承機能を活用してすべてのプロジェクトイルを同一の基本設定に基づいて構築できます。&lt;/p&gt;
&lt;p&gt;使用するノード：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&lt;i class="gd-Area2D"&gt;&lt;/i&gt; Area2D: Missile
&lt;i class="gd-Sprite2D"&gt;&lt;/i&gt; Sprite2D
&lt;i class="gd-CollisionShape2D"&gt;&lt;/i&gt; CollisionShape2D
&lt;i class="gd-Timer"&gt;&lt;/i&gt; Timer: Lifetime
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;テクスチャについては、お好きな画像を自由に使用できます。一例をご紹介します。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-16ac6d3cf4ba2b70dfc0bfc4af6528cf" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/missile.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-16ac6d3cf4ba2b70dfc0bfc4af6528cf"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/missile.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ノードの設定を行い、スプライトのテクスチャと衝突形状を構成します。&lt;i class="gd-Sprite2D"&gt;&lt;/i&gt;&lt;code&gt;Sprite2D&lt;/code&gt;ノードは必ず &lt;code&gt;90°&lt;/code&gt; 回転させ、右向きになるように調整してください。これにより、親オブジェクトの「前方」方向と一致するようになります。&lt;/p&gt;
&lt;p&gt;スクリプトを追加し、&lt;i class="gd-Area2d"&gt;&lt;/i&gt;&lt;code&gt;Area2D&lt;/code&gt;の&lt;code&gt;body_entered&lt;/code&gt;シグナルと&lt;i class="gd-Timer"&gt;&lt;/i&gt;&lt;code&gt;Timer&lt;/code&gt;の&lt;code&gt;timeout&lt;/code&gt;シグナルを接続してください。&lt;/p&gt;
&lt;p&gt;以下に開始スクリプトを示します。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;extends&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Area2D&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d08770"&gt;@export&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; speed &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;350&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Vector2&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;ZERO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; acceleration &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Vector2&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;ZERO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;start&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;_transform&lt;span style="color:#eceff4"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; global_transform &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; _transform
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; transform&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;x &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; speed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_physics_process&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;delta&lt;span style="color:#eceff4"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;+=&lt;/span&gt; acceleration &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; delta
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; velocity&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;clamped&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;speed&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rotation &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; velocity&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;angle&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; position &lt;span style="color:#81a1c1"&gt;+=&lt;/span&gt; velocity &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; delta
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_on_Missile_body_entered&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;body&lt;span style="color:#eceff4"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#88c0d0"&gt;queue_free&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_on_Lifetime_timeout&lt;/span&gt;&lt;span style="color:#eceff4"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#88c0d0"&gt;queue_free&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;この設定により、発射時に直線軌道で移動する「単純な」ロケットが作成されます。この投射物を使用するためには、インスタンス化した後、&lt;code&gt;start()&lt;/code&gt; メソッドを呼び出し、目的の位置と方向を設定するために適切な &lt;code&gt;Transform2D&lt;/code&gt; を指定が必要です。&lt;/p&gt;
&lt;p&gt;詳細については以下の &lt;a href="#%e9%96%a2%e9%80%a3%e3%83%ac%e3%82%b7%e3%83%94"&gt;関連レシピ&lt;/a&gt; セクションをご覧ください。&lt;/p&gt;
&lt;p&gt;ターゲット捜索動作を変更するため、&lt;code&gt;acceleration&lt;/code&gt;（加速度）を利用します。ただし、ミサイルが「一瞬で方向転換する」のは避けたいので、制御する「ステアリング力」を調整する変数を追加してください。この設定により、異なる挙動に対応した旋回半径を調整できるようになります。また、ミサイルが追跡対象を把握するための&lt;code&gt;target&lt;/code&gt;変数も必要です。これも&lt;code&gt;start()&lt;/code&gt;関数内で適切に初期化します。&lt;/p&gt;</description></item><item><title>状況に基づく操縦</title><link>https://kamera25.github.io/godot_recipes/4.x/ja/ai/context_map/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kamera25.github.io/godot_recipes/4.x/ja/ai/context_map/index.html</guid><description>&lt;div class="box notices cstyle tips"&gt;
&lt;div class="box-label"&gt;ℹ️ 留意事項&lt;/div&gt;
&lt;div class="box-content"&gt;
&lt;p&gt;この記事は Godot 3から Godot 4 へ内容の書き換え中です。
Godot4では存在しない変数、関数が含まれている場合があります。もしその場合はリポジトリの&lt;a href="https://github.com/kamera25/godot_recipes/issues" target="_blank"&gt;Issues&lt;/a&gt;までご報告ください。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="課題"&gt;課題&lt;/h2&gt;
&lt;p&gt;経路を追従し、障害物を避け、世界を移動する方法について他の判断もできるAI制御オブジェクトがほしい。&lt;/p&gt;
&lt;h2 id="解決策"&gt;解決策&lt;/h2&gt;
&lt;p&gt;「ステアリング挙動」とは、この問題を解決するために使用可能な様々なアルゴリズムの総称です。どの手法を採用するかは、ゲームの特性、オブジェクトが存在する世界の種類、そして求める「知性」のレベルによって異なります。&lt;/p&gt;
&lt;p&gt;この例では、「状況に基づく振舞い(Context Behavior)」と呼ばれる手法を採用します。これは、オブジェクトが移動方法を選択するために十分なワールドの情報を得ることを目的とするものです。本テーマについてさらに詳しく知りたい方は、以下の関連リンクを参照してください。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://andrewfray.wordpress.com/2013/03/26/context-behaviours-know-how-to-share/" target="_blank"&gt;アンドリュー・フレイ: 状況に基づく振舞いがどのように共有されるべきか&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://jameskeats.com/portfolio/contextbhvr.html" target="_blank"&gt;ジェームズ・キーツ：AIコンテキスト行動管理&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;このデモでは、汎用的な「エージェント」オブジェクトを使用します。実際のゲームであれば、これはレースコースを走る車、ダンジョンを巡回するモンスター、あるいは他の種類のゲーム内エンティティなどに相当するでしょう。エージェントは &lt;code&gt;&lt;i class="gd-CharacterBody2D"&gt;&lt;/i&gt;CharacterBody2D&lt;/code&gt; を使用しますが、覚えておいていただきたいのは、このテクニックはどんな種類のオブジェクトにも適用可能だということです。アルゴリズム自体は対象が移動する方向を選択する方法に関するものであり、実際の移動方法は完全に別個の問題です。&lt;/p&gt;
&lt;h3 id="アルゴリズムについて"&gt;アルゴリズムについて&lt;/h3&gt;
&lt;p&gt;まず、エージェントがすべての方向に放射線状に広がる複数のレイを持っていると仮定します（使用する本数については後で説明します。とりあえずここでは8本を使用してください）&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-48542f58fba24aeeab5e48e8e69e7693" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_01.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-48542f58fba24aeeab5e48e8e69e7693"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_01.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;エージェントのスクリプト内では、エージェントが移動したい方向を追跡するための配列&lt;code&gt;interest&lt;/code&gt;を定義します。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-2bdae5a814094326392fabaf43c08c5b" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_04.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-2bdae5a814094326392fabaf43c08c5b"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_04.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;もちろん、全て同じ方向なら動けません。あらゆる方向に均等に移動したいはずです！そこで、特定の方向への優先性があると仮定します。主に前進したい場合を考えます。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-ef7709118239dfd808764934f2c31b73" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_03.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-ef7709118239dfd808764934f2c31b73"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_03.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この場合、&lt;code&gt;interest&lt;/code&gt;配列は以下のようになります。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-2e6f0bbfa05f641939fd8fcaa306e856" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_05.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-2e6f0bbfa05f641939fd8fcaa306e856"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_05.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最も強い願望は前進することですが、左前方や右前方も許容範囲内です。しかし、障害物が現れた場合は？&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-2bc923dd43346cd445540e83b3921572" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_06.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-2bc923dd43346cd445540e83b3921572"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_06.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;次に、好ましくない方向を示す第2の配列&lt;code&gt;danger&lt;/code&gt;を導入します。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-8599b3033e716c8e484c73a94771f4a7" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_07.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-8599b3033e716c8e484c73a94771f4a7"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_07.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;これら2つの配列を組み合わせることで、&lt;code&gt;danger(危険度)&lt;/code&gt;に含まれる&lt;code&gt;interest(興味度)&lt;/code&gt;方向を除去することが可能です。残った&lt;code&gt;interest&lt;/code&gt;方向を合計すると、障害物から離れる新しい方向ベクトルが得られます。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-6409e423f8ff71afcb3800e8e8f3ab53" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_08.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-6409e423f8ff71afcb3800e8e8f3ab53"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/ai_context_08.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;要約すると：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;オブジェクトの&lt;code&gt;interst(関心度)&lt;/code&gt;方向を特定する&lt;/li&gt;
&lt;li&gt;&lt;code&gt;danger(危険度)&lt;/code&gt;を含む方向をすべて特定する&lt;/li&gt;
&lt;li&gt;危険な&lt;code&gt;interest(関心度)&lt;/code&gt;方向がある場合はすべて除外する&lt;/li&gt;
&lt;li&gt;残った&lt;code&gt;interest(関心度)&lt;/code&gt;方向を合算して新たな進行方向を決定する&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="興味を見つける方法"&gt;興味を見つける方法&lt;/h3&gt;
&lt;p&gt;これはエージェントの目標内容によって異なります。もしその目的が『プレイヤーを追跡すること』であれば、&lt;code&gt;interest&lt;/code&gt;の値はプレイヤー方向へ高くなるべきです。複数のターゲットを設定することも可能で、より近い目標ほど高い興味を持ちますが、障害物によって無効化された場合、スコアが低い他の目標が優先されます。&lt;/p&gt;
&lt;p&gt;このデモでは、何らかのレースゲームを作っていると仮定します。AI制御の車はサーキットを周回が必要です。その&lt;code&gt;interest&lt;/code&gt;配列はコースに沿って前方を指すように設定すべきで、そうしないと逆走を開始してしまいます。&lt;/p&gt;
&lt;p&gt;これを実現する方法は複数ありますが、エージェントが実装の詳細を知る必要がないよう、トラックがどの方向に進むべきかを位置情報に基づいて指示するシステムを構築します。いつでも「どの方向が正しいか」と聞けば、トラックがその指示を伝えてくれます。&lt;/p&gt;
&lt;h3 id="コード例"&gt;コード例&lt;/h3&gt;
&lt;p&gt;以下にエージェントのコードを示します。まずはエクスポートした値から始めてください。移動パラメーターと、後で容易に調整できるようにしたいその他の値です。例えば &lt;code&gt;look_ahead&lt;/code&gt; は、&lt;code&gt;danger&lt;/code&gt; レイが障害物を検出する範囲を指定します。&lt;/p&gt;
&lt;p&gt;※注：&lt;code&gt;num_rays(レイの数)&lt;/code&gt;は調整可能な設定となっています。これにより、用途に最適な数値を見つけることができます。以下では、レイの数が多い場合のメリット・デメリットについて詳しく解説します。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;extends&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;CharacterBody2D&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d08770"&gt;@export&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; max_speed &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;350&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d08770"&gt;@export&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; steer_force &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d08770"&gt;@export&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; look_ahead &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d08770"&gt;@export&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; num_rays &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;# context array&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; ray_directions &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#eceff4"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; interest &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#eceff4"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; danger &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#eceff4"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; chosen_dir &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Vector2&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;ZERO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Vector2&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;ZERO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; acceleration &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Vector2&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;ZERO
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;次の &lt;code&gt;_ready()&lt;/code&gt; 関数では、配列を適切にサイズ調整し、&lt;code&gt;ray_directions&lt;/code&gt; 配列に実際のレイベクトルを格納します。これらは &lt;code&gt;num_rays&lt;/code&gt; に基づいて円周上に均等に配置されます。最初は回転していない状態なので、&lt;code&gt;Vector2.RIGHT&lt;/code&gt; が前方方向となります。&lt;/p&gt;</description></item><item><title>追いかけるペット</title><link>https://kamera25.github.io/godot_recipes/4.x/ja/ai/pet_following/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kamera25.github.io/godot_recipes/4.x/ja/ai/pet_following/index.html</guid><description>&lt;h2 id="課題"&gt;課題&lt;/h2&gt;
&lt;p&gt;ゲーム要素としてペットやミニオンを追加してください。なので、キャラクターに追従させる必要があります。&lt;/p&gt;
&lt;p&gt;&lt;video controls src='https://kamera25.github.io/godot_recipes/4.x/img/pet_follow.webm'&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id="解決策"&gt;解決策&lt;/h2&gt;
&lt;p&gt;まず、キャラクターに &lt;i class="gd-Marker2D"&gt;&lt;/i&gt;&lt;code&gt;Marker2D&lt;/code&gt; を追加してください。このマーカーは、ペットがプレイヤーの近くに「滞在したい」場所を示すものです。&lt;/p&gt;
&lt;p&gt;
&lt;a href="#image-7e71c9feb1e0bf05aa44e2e69121de5a" class="lightbox-link"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/pet_follow_01.png" alt="alt" style="height: auto; width: auto;" loading="lazy"&gt;
&lt;/a&gt;
&lt;a href="javascript:history.back();" class="lightbox" id="image-7e71c9feb1e0bf05aa44e2e69121de5a"&gt;
&lt;img src="https://kamera25.github.io/godot_recipes/4.x/img/pet_follow_01.png" alt="alt" class="lightbox-image" loading="lazy"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;この例では、&lt;i class="gd-Sprite2D"&gt;&lt;/i&gt;&lt;code&gt;Sprite2D&lt;/code&gt;の子要素として設定しています。これはキャラクターのコード内で &lt;code&gt;$Sprite2D.scale.x = -1&lt;/code&gt; を使用して左移動時に水平方向を反転させているためです。マーカーはスプライトの子要素であるため、同様に反転表示されます。&lt;/p&gt;
&lt;h3 id="ペット用スクリプト"&gt;ペット用スクリプト&lt;/h3&gt;
&lt;p&gt;以下はペット用の台本です。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;extends&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;CharacterBody2D&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d08770"&gt;@export&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; parent &lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;CharacterBody2D&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; speed &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;25&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#d08770"&gt;@onready&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; follow_point &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; parent&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;get_node&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;Sprite2D/FollowPoint&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;parent&lt;/code&gt;変数には、ペットが追従すべきキャラクターへの参照情報が格納されています。その後、そのノードから&lt;code&gt;FollowPoint&lt;/code&gt;を取得し、&lt;code&gt;_physics_process()&lt;/code&gt;関数内でその位置情報を取得します。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;func&lt;/span&gt; &lt;span style="color:#88c0d0"&gt;_physics_process&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;delta&lt;span style="color:#eceff4"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt; target &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; follow_point&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;global_position
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;Vector2&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;ZERO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; position&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;distance_to&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;target&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#b48ead"&gt;5&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; velocity &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; position&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;direction_to&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;target&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;*&lt;/span&gt; speed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; velocity&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;x &lt;span style="color:#81a1c1"&gt;!=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $Sprite2D&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;scale&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;x &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;sign&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;velocity&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;x&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; velocity&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;length&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#b48ead"&gt;0&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $AnimationPlayer&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;play&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;run&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;else&lt;/span&gt;&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $AnimationPlayer&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#88c0d0"&gt;play&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;idle&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#88c0d0"&gt;move_and_slide&lt;/span&gt;&lt;span style="color:#eceff4"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;目標地点に近い場合は、ペットの移動を停止します。&lt;/p&gt;
&lt;h3 id="障害物の回避方法"&gt;障害物の回避方法&lt;/h3&gt;
&lt;p&gt;ワールドによっては、ペットが障害物に引っかかってしまう場合があります。より堅牢な追従機能が必要な場合は、ナビゲーションシステムをご利用ください。具体的な実装例については&lt;a href="https://kamera25.github.io/godot_recipes/4.x/ja/ai/tilemap_navigation/"&gt;タイルマップナビゲーション&lt;/a&gt;を参照してください。&lt;/p&gt;
&lt;h2 id="プロジェクトのダウンロード"&gt;&lt;i class="fas fa-code-branch"&gt;&lt;/i&gt; プロジェクトのダウンロード&lt;/h2&gt;
&lt;p&gt;プロジェクトのサンプルコードはこちらからダウンロードできます。&lt;a href="https://github.com/godotrecipes/ai_behavior_demos" target="_blank"&gt;https://github.com/godotrecipes/ai_behavior_demos&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>