Unity NavMeshでマス目ごとに停止しながらターゲットに向かうエージェントの実装方法
このチュートリアルでは、UnityでNavMeshエージェントを使用し、ターゲットに向かってマス目に沿って1マスずつ進みながら、一時停止を繰り返す動作を実現します。エージェントが各マスの中心に到達するごとに停止し、指定の時間待機してから再び移動を再開するようにします。
実行結果
このチュートリアルを進めた時の動きを先に見てみましょう
チュートリアル
ステップ1: NavMeshエージェントの設定
3Dプロジェクトを新規で作成します
プロジェクト名はGridPathFollowerSampleとしておきます
シーンにPlaneオブジェクトを追加
シーンに「3D Object > Plane」を選択して、平面を追加します。これはエージェントが移動する床として使用します。
NavMeshをベイク
Hierarkyウィンドウで右クリックし、「AI > NavMesh Surface」を選択して、エージェントの移動エリアを作成します
「Bake」ボタンを押します。これでPlaneの上がNavMeshエリアとして設定され、エージェントが移動できるようになります。
エージェントオブジェクトを作成
Planeの上に移動するオブジェクトとして「3D Object > Capsule」などのオブジェクトを追加し、「NavMeshAgent」コンポーネントをアタッチします。
ターゲットオブジェクトを作成
Capsuleが追跡するターゲットを設定するため、「3D Object > Cube」などのオブジェクトを追加し、これを移動先ターゲットとして使用します。
ステップ2: スクリプトの作成
スクリプトを作成
新しいC#スクリプトを作成し、「GridBasedAgent.cs」と名付けます。
スクリプトをエージェントオブジェクトにアタッチ
エージェントオブジェクト(Capsule)に、作成した「GridBasedAgent.cs」スクリプトをアタッチします。
ステップ3: マス目ごとの移動ロジックの実装
以下のコードをGridBasedAgent.cs
に追加し、エージェントがX軸とZ軸のみに沿ってターゲットに最短距離で向かうようにします。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class GridBasedAgent : MonoBehaviour
{
public Transform target; // ターゲットオブジェクト
public float waitTime = 1.0f; // 各マスでの待機時間
public float gridSize = 1.0f; // マス目のサイズ
private NavMeshAgent agent;
private Queue<Vector3> pathPoints; // マス目ごとの経路
private bool isWaiting = false;
public float arrivalThreshold = 0.2f; // マスへの到達とみなす距離
void Start()
{
agent = GetComponent<NavMeshAgent>();
CalculateOptimizedGridPath(); // 最短経路を計算
}
void Update()
{
if (!isWaiting && pathPoints != null && pathPoints.Count > 0)
{
Vector3 nextPoint = pathPoints.Peek(); // 次のマスの位置を確認
// Y軸を無視して距離を計算
Vector2 currentPos2D = new Vector2(transform.position.x, transform.position.z);
Vector2 nextPoint2D = new Vector2(nextPoint.x, nextPoint.z);
// 現在の位置が目的のマスに到達しているか
if (Vector2.Distance(currentPos2D, nextPoint2D) < arrivalThreshold)
{
pathPoints.Dequeue(); // 到達したマスを削除
StartCoroutine(WaitAndMoveToNextPoint()); // 1マスごとに停止
}
else
{
agent.destination = nextPoint; // 次のマスへ移動
}
}
}
// ターゲットまでの最短経路をXとZに分解して計算
private void CalculateOptimizedGridPath()
{
pathPoints = new Queue<Vector3>();
Vector3 currentPos = transform.position;
Vector3 targetPos = target.position;
while (Mathf.Abs(targetPos.x - currentPos.x) > gridSize || Mathf.Abs(targetPos.z - currentPos.z) > gridSize)
{
// X方向とZ方向の距離を比較して、短い方を優先
if (Mathf.Abs(targetPos.x - currentPos.x) > Mathf.Abs(targetPos.z - currentPos.z))
{
// X方向に移動
currentPos = new Vector3(
currentPos.x + Mathf.Sign(targetPos.x - currentPos.x) * gridSize,
currentPos.y,
currentPos.z
);
}
else
{
// Z方向に移動
currentPos = new Vector3(
currentPos.x,
currentPos.y,
currentPos.z + Mathf.Sign(targetPos.z - currentPos.z) * gridSize
);
}
pathPoints.Enqueue(currentPos); // キューに現在位置を追加
}
}
// 各マスで停止して待機するコルーチン
private IEnumerator WaitAndMoveToNextPoint()
{
isWaiting = true;
agent.isStopped = true; // エージェントを停止
yield return new WaitForSeconds(waitTime); // 指定の時間待機
agent.isStopped = false; // エージェントの移動を再開
isWaiting = false;
}
}
コードの解説
- CalculateOptimizedGridPathメソッド
target
オブジェクトまでの経路を1マスごとに計算し、X軸とZ軸のみに沿って移動するようにしています。target
の位置に対して、X方向またはZ方向の距離が短い方を優先して進むため、エージェントは最短経路で移動します。
- Updateメソッド
- エージェントが次のマスに到達した際に停止し、
waitTime
だけ待機するようにしています。 arrivalThreshold
内に到達した場合に、キューから次のマスを取り出し、コルーチンを呼び出して待機させます。
- エージェントが次のマスに到達した際に停止し、
- WaitAndMoveToNextPointコルーチン
- 各マスごとにエージェントを停止し、指定の
waitTime
後に再び次のマスへ移動します。
- 各マスごとにエージェントを停止し、指定の
ステップ4: 実行と確認
- ターゲットオブジェクトの設定
- エージェントオブジェクト(例: Capsule)を選択し、インスペクターでスクリプトの「Target」にターゲットオブジェクト(例: Cube)をドラッグして設定します。
- 再生して動作確認
- 再生ボタンを押してシーンを実行し、エージェントがターゲットに向かってX方向かZ方向にのみ移動しながら、各マスで停止する様子を確認します。
注意点
- waitTime: 各マスでの待機時間を調整して、エージェントの停止時間を設定できます。
- gridSize: 1マスのサイズを設定します。通常は1.0に設定すると良いですが、環境に応じて変更してください。
- arrivalThreshold: マスへの到達距離の閾値を適切に調整し、エージェントが意図通りに停止するようにします。
このチュートリアルに従えば、エージェントがターゲットに向かって最短経路をX・Z方向でのみ移動し、各マスで待機する動作が実現できます。
ディスカッション
コメント一覧
まだ、コメントがありません