unity-ai-navigation について
Unity 開発者向けに、Unity 6 の AI ナビゲーションと推論をまとめたスキルガイドです。NavMesh の構築、経路探索、動的障害物、ONNX モデルを扱います。
主な機能
- 01NavMesh の構築とベイク
- 02Agent の経路探索と移動
- 03動的障害物の管理
- 04Off-Mesh Link の設定
- 05Sentis による ONNX 推論
活用シーン
- 01実行時または編集時の NavMesh 設定
- 02キャラクター移動と経路状態の確認
- 03動的障害物やサーフェス間リンクの処理
- 04Unity での ONNX モデル実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nice-wolf-studio/ unity-claude-skills --skill unity-ai-navigationインストール後、Claude Code で/unity-ai-navigationを入力して読み込まれたか確認します。
同梱ファイルreferences/navmesh-guide.mdreferences/sentis-ml.md
詳細
Unity 6 AI とナビゲーションガイド
ソース:Unity 6.3 LTS ドキュメント(6000.3)
AI ナビゲーションの概要
パッケージ: com.unity.ai.navigation(Unity 6000.3 向け v2.0.11)
AI Navigation パッケージは、NavMesh ベースのナビゲーションと経路探索を可能にする高水準のコンポーネントシステムです。ランタイムおよび編集時の NavMesh 構築、動的な障害物の管理、特殊なアクション(ジャンプ、ドアなど)向けのリンクシステムに対応しています。
コアコンポーネント
| コンポーネント | 用途 |
|---|---|
| NavMeshSurface | 特定のエージェントタイプ向けに NavMesh を定義して構築します |
| NavMeshAgent | キャラクターの経路探索と移動 |
| NavMeshObstacle | 動的な障害物の回避 |
| NavMeshModifier | トランスフォーム階層に基づいて NavMesh の生成に影響を与えます |
| NavMeshModifierVolume | ボリュームに基づいて NavMesh の生成に影響を与えます |
| NavMeshLink | 同一または異なる NavMesh サーフェスを接続します |
NavMesh のセットアップ
NavMesh のベイク
- GameObject に NavMeshSurface コンポーネントを追加します
- Agent Type を設定します(このサーフェスを使用できるエージェントを指定します)
- Use Geometry を Render Meshes または Physics Colliders に設定します
- Collect Objects モード(All、Volume、Current Hierarchy、NavMeshModifier only)を設定します
- Bake をクリックするか、ランタイムに
BuildNavMesh()を呼び出します
NavMeshSurface のプロパティ
| プロパティ | 説明 |
|---|---|
| Agent Type | このサーフェスを使用できる NavMesh Agent の設定 |
| Default Area | Walkable(デフォルト)、Not Walkable、Jump、および29種類のカスタムタイプ |
| Use Geometry | Render Meshes または Physics Colliders(コライダーを使用すると、エッジにより近いナビゲーションが可能です) |
| Generate Links | ベイク中に収集した GameObject 間の接続を自動作成します |
| Collect Objects | すべての GameObject、Volume、Current Hierarchy、NavMeshModifier only |
| Include Layers | レイヤーに基づいて GameObject をフィルターします(デフォルト:Everything) |
高度なベイクパラメーター
| パラメーター | 説明 |
|---|---|
| Override Voxel Size | 精度(デフォルト:エージェントの半径あたり3ボクセル) |
| Override Tile Size | タイルの寸法(デフォルト:256ボクセル)。小さいほどカービングの精度が向上します |
| Minimum Region Area | しきい値を下回る、接続されていないメッシュセグメントを削除します |
| Build Height Mesh | キャラクター配置用の高さデータを生成します |
ベイク中は、NavMeshAgent または NavMeshObstacle を持つ GameObject がシステムによって除外されます。
ランタイム NavMesh ベイク
using UnityEngine;
using Unity.AI.Navigation;
public class RuntimeNavMeshBaker : MonoBehaviour
{
NavMeshSurface surface;
void Start()
{
surface = GetComponent<NavMeshSurface>();
surface.BuildNavMesh();
}
public void RebakeNavMesh()
{
surface.UpdateNavMesh(surface.navMeshData);
}
}
NavMeshAgent
NavMeshAgent コンポーネントは、経路探索と移動制御の両方を処理します。
追加方法:Add Component > Navigation > NavMesh Agent
基本的な移動
using UnityEngine;
using UnityEngine.AI;
public class MoveTo : MonoBehaviour
{
public Transform goal;
void Start()
{
NavMeshAgent agent = GetComponent<NavMeshAgent>();
agent.destination = goal.position;
}
}
エージェントのプロパティ
ステアリング: Speed、Angular Speed、Acceleration、Stopping Distance、Auto Braking
障害物回避: Radius、Height、Quality(None から High)、Priority(0~99。数値が小さいほど優先度が高くなります)
エージェントは優先度の高いエージェントを避け、優先度の低いエージェントを無視します。
経路探索: Auto Traverse OffMesh Link、Auto Repath、Area Mask
エージェントのスクリプトパターン
using UnityEngine;
using UnityEngine.AI;
public class AIController : MonoBehaviour
{
NavMeshAgent agent;
void Start() { agent = GetComponent<NavMeshAgent>(); }
public void MoveToTarget(Vector3 target) { agent.SetDestination(target); }
bool HasReachedDestination()
{
if (!agent.pathPending
&& agent.remainingDistance <= agent.stoppingDistance
&& (!agent.hasPath || agent.velocity.sqrMagnitude == 0f))
return true;
return false;
}
public void StopMoving() { agent.isStopped = true; }
public void ResumeMoving() { agent.isStopped = false; }
public void WarpTo(Vector3 position) { agent.Warp(position); }
}
部分経路
目的地に到達できない場合、エージェントは到達可能な最寄りの場所まで部分経路を生成します。
if (agent.pathStatus == NavMeshPathStatus.PathPartial)
Debug.Log("Destination unreachable, using partial path");
else if (agent.pathStatus == NavMeshPathStatus.PathInvalid)
Debug.Log("No valid path found");
NavMeshObstacle
エージェントが回避する動的な障害物を定義します。追加方法:Add Component > Navigation > NavMesh Obstacle
形状: Box(Center + Size)または Capsule(Center + Radius + Height)
カービング
| プロパティ | 説明 |
|---|---|
| Move Threshold | 移動する障害物の更新を開始する距離 |
| Time To Stationary | 停止状態と判定されるまでの秒数 |
| Carve Only Stationary | 移動していないときのみカービングします |
- カービングあり: NavMesh のトポロジを動的に変更します(樽、木箱、ドアなど)
- カービングなし: メッシュを変更せずに除外ゾーンを作成します(移動するキャラクターなど)
using UnityEngine;
using UnityEngine.AI;
public class DynamicObstacle : MonoBehaviour
{
NavMeshObstacle obstacle;
void Start()
{
obstacle = GetComponent<NavMeshObstacle>();
obstacle.carving = true;
obstacle.carveOnlyStationary = true;
}
public void SetBlocking(bool blocking) { obstacle.enabled = blocking; }
}
オフメッシュリンク(NavMeshLink)
個別の NavMesh サーフェスを接続します。ドア、ジャンプポイント、段差、はしごなどに使用します。
追加方法:GameObject > AI > NavMesh Link または Add Component > Navigation > NavMesh Link
| プロパティ | 説明 |
|---|---|
| Agent Type | 通行できるエージェントの種類 |
| Start/End Transform | リンクの端に配置する GameObject |
| Width | リンクの幅 |
| Bidirectional | 双方向の通行 |
| Area Type | Walkable、Not Walkable、または Jump |
| Activated | リンクの使用可否を制御 |
カスタムリンクの通行
using UnityEngine;
using UnityEngine.AI;
using System.Collections;
public class CustomLinkTraversal : MonoBehaviour
{
NavMeshAgent agent;
void Start()
{
agent = GetComponent<NavMeshAgent>();
agent.autoTraverseOffMeshLink = false;
}
void Update()
{
if (agent.isOnOffMeshLink) StartCoroutine(TraverseLink());
}
IEnumerator TraverseLink()
{
OffMeshLinkData linkData = agent.currentOffMeshLinkData;
Vector3 startPos = agent.transform.position;
Vector3 endPos = linkData.endPos + Vector3.up * agent.baseOffset;
float elapsed = 0f, duration = 0.5f;
while (elapsed < duration)
{
float t = elapsed / duration;
agent.transform.position = Vector3.Lerp(startPos, endPos, t)
+ Vector3.up * Mathf.Sin(t * Mathf.PI) * 2f;
elapsed += Time.deltaTime;
yield return null;
}
agent.CompleteOffMeshLink();
}
}
Unity Sentis の概要
パッケージ: com.unity.sentis (v2.1) -- 現在は Inference Engine (com.unity.ai.inference) に名称変更されています
Unity のすべてのプラットフォームで、GPU/CPU 上で ONNX モデル(opset 7-15)を実行するためのニューラルネットワーク推論ライブラリです。
基本的なワークフロー
using UnityEngine;
using Unity.Sentis;
public class MLInference : MonoBehaviour
{
public ModelAsset modelAsset;
Model runtimeModel;
Worker worker;
void Start()
{
runtimeModel = ModelLoader.Load(modelAsset);
worker = new Worker(runtimeModel, BackendType.GPUCompute);
}
void RunInference()
{
Tensor<float> input = TextureConverter.ToTensor(
Resources.Load("image") as Texture2D);
worker.Schedule(input);
Tensor<float> output = worker.PeekOutput() as Tensor<float>;
input.Dispose();
}
void OnDestroy() { worker?.Dispose(); }
}
バックエンドの種類
| バックエンド | パフォーマンス | 備考 |
|---|---|---|
| GPUCompute | 最速(GPU) | SystemInfo.supportsComputeShaders を確認してください |
| CPU | 最速(CPU) | WebGL では低速です(Burst から WASM にコンパイル) |
| GPUPixel | 低速 | コンピュートシェーダーがない場合のフォールバック |
API の詳細については、skills/unity-ai-navigation/references/sentis-ml.md を参照してください。
よくある AI パターン
シンプルなステートマシン
using UnityEngine;
using UnityEngine.AI;
public enum AIState { Idle, Patrol, Chase, Attack }
public class AIStateMachine : MonoBehaviour
{
public AIState currentState = AIState.Idle;
public Transform[] patrolPoints;
public float chaseRange = 10f, attackRange = 2f;
NavMeshAgent agent;
Transform player;
int patrolIndex;
void Start()
{
agent = GetComponent<NavMeshAgent>();
player = GameObject.FindWithTag("Player").transform;
}
void Update()
{
float dist = Vector3.Distance(transform.position, player.position);
switch (currentState)
{
case AIState.Idle:
if (dist < chaseRange) currentState = AIState.Chase;
else if (patrolPoints.Length > 0) currentState = AIState.Patrol;
break;
case AIState.Patrol:
agent.SetDestination(patrolPoints[patrolIndex].position);
if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance)
patrolIndex = (patrolIndex + 1) % patrolPoints.Length;
if (dist < chaseRange) currentState = AIState.Chase;
break;
case AIState.Chase:
agent.SetDestination(player.position);
if (dist < attackRange) currentState = AIState.Attack;
else if (dist > chaseRange * 1.5f) currentState = AIState.Patrol;
break;
case AIState.Attack:
agent.isStopped = true;
if (dist > attackRange) { agent.isStopped = false; currentState = AIState.Chase; }
break;
}
}
}
ビヘイビアツリーのノード
public enum NodeState { Running, Success, Failure }
public abstract class BTNode { public abstract NodeState Evaluate(); }
public class Selector : BTNode
{
BTNode[] children;
public Selector(params BTNode[] children) { this.children = children; }
public override NodeState Evaluate()
{
foreach (var child in children)
{
var result = child.Evaluate();
if (result != NodeState.Failure) return result;
}
return NodeState.Failure;
}
}
public class Sequence : BTNode
{
BTNode[] children;
public Sequence(params BTNode[] children) { this.children = children; }
public override NodeState Evaluate()
{
foreach (var child in children)
{
var result = child.Evaluate();
if (result != NodeState.Success) return result;
}
return NodeState.Success;
}
}
NavMesh クエリ
using UnityEngine;
using UnityEngine.AI;
public class NavMeshQueries : MonoBehaviour
{
public Vector3 GetNearestNavMeshPoint(Vector3 pos, float maxDist)
{
NavMeshHit hit;
return NavMesh.SamplePosition(pos, out hit, maxDist, NavMesh.AllAreas)
? hit.position : pos;
}
public bool IsOnNavMesh(Vector3 pos)
{
NavMeshHit hit;
return NavMesh.SamplePosition(pos, out hit, 0.1f, NavMesh.AllAreas);
}
public bool CanReachTarget(Vector3 start, Vector3 end)
{
NavMeshPath path = new NavMeshPath();
NavMesh.CalculatePath(start, end, NavMesh.AllAreas, path);
return path.status == NavMeshPathStatus.PathComplete;
}
public Vector3 GetRandomNavMeshPoint(Vector3 center, float range)
{
Vector3 dir = Random.insideUnitSphere * range + center;
NavMeshHit hit;
return NavMesh.SamplePosition(dir, out hit, range, NavMesh.AllAreas)
? hit.position : center;
}
}
アンチパターン
- 毎フレーム NavMesh をベイクする --
BuildNavMesh()は処理コストが高いため、ジオメトリが変更されたときのみ呼び出してください。差分更新にはUpdateNavMesh()を使用してください。 - pathStatus を確認しない -- 必ず
agent.pathStatusを確認してください。パスが部分的、または無効な場合、エージェントは気づかれないまま動けなくなることがあります。 - ガードなしで Update 内に移動先を設定する -- 毎フレームパスを再計算すると CPU を無駄に消費します。ターゲットが大きく移動した場合にのみ更新してください。
- エージェントに NavMeshObstacle を付ける -- NavMeshAgent も持つ GameObject に NavMeshObstacle を追加しないでください。エージェントはすでに互いを回避します。
- エリアマスクを忘れる -- 適切な Area Mask がないエージェントは、立ち入り制限区域を通り抜ける可能性があります。
- すべてをカービングする -- カービングは処理コストが高いため、エージェントが自然に迂回できる障害物には、カービングを行わない障害物を使用してください。
- NavMeshSurface がない -- NavMeshSurface がなければ NavMesh はありません。エージェントは移動しません。
- Sentis のワーカーを破棄しない -- 必ず
OnDestroy()でworker.Dispose()を呼び出してください。 - WebGL で CPU バックエンドを使用する -- Burst が WASM にコンパイルされるため、ML 推論が非常に遅くなります。
主要 API クイックリファレンス
| クラス | 名前空間 | 用途 |
|---|---|---|
NavMeshAgent | UnityEngine.AI | パスファインディングと移動 |
NavMeshObstacle | UnityEngine.AI | 動的な障害物 |
NavMesh | UnityEngine.AI | 静的なクエリとサンプリング |
NavMeshPath | UnityEngine.AI | 計算済みパスのデータ |
NavMeshHit | UnityEngine.AI | レイキャスト/サンプリング結果 |
NavMeshSurface | Unity.AI.Navigation | NavMesh のベイク |
NavMeshModifier | Unity.AI.Navigation | オブジェクト単位のオーバーライド |
NavMeshModifierVolume | Unity.AI.Navigation | ボリューム単位のオーバーライド |
NavMeshLink | Unity.AI.Navigation | サーフェスの接続 |
ModelAsset | Unity.Sentis | ONNX モデルの参照 |
ModelLoader | Unity.Sentis | 実行時のモデル読み込み |
Worker | Unity.Sentis | 推論エンジン |
BackendType | Unity.Sentis | GPUCompute、CPU、GPUPixel |
Tensor<T> | Unity.Sentis | 入力/出力データ |
関連スキル
unity-foundations-- GameObject、コンポーネント、シーン階層unity-scripting-- C# スクリプトのパターン、MonoBehaviour のライフサイクルunity-physics-- コライダー、レイキャスト、NavMesh との物理演算の統合