【Unity】再入門!NavMeshAgent (解説動画あり)
「とっつきにくい印象」
「インターフェースも初めて触るとわかりにくい」
「メカニズムを理解しないと挙動も安定させにくく
制限も多い」
公式からも「これだからNavMeshは…」とぼやかれる
でも使えるととっても便利
そんなNavMeshAgentについて今日はお話したいと思います
記事の最後に今回は解説動画もつけてみました
あわせて見ていただくと理解が進むと思います
1.なぜナビメッシュを使うのか
冒頭、苦言を呈しましたが
基本を習得すると便利だからです
今回作成しているゲームのNPCの行動アルゴリズムは
ほとんどNavMeshAgentで作成するので今回の記事では
NavMeshAgentの「良いところ」をお伝え出来ればと思います
チュートリアルの動画も作りましたので
まだ触れたことのない方や、触ってみたけど良くわからなかった方は
ご覧になってください
2.そもそも、ナビメッシュって何?
NavMesh(ナビメッシュ)は、ゲーム開発においてキャラクターや
AIエージェントの移動を管理するための重要な要素です
NavMeshは、ゲーム内の地形や障害物などの情報を含んだ3Dメッシュの
データ構造であり、エージェントが移動可能な領域を表現します
基本は3Dプロジェクトで利用します
(2Dプロジェクトでも使えなくはない)移動することのできる「エリア」をメッシュ上に作成します
PCに用いることで自然に障害物を避けて移動させることができます
3.NavMeshAgent導入のメリットとデメリット
私なりに導入のメリットを3点あげてみます
リアルタイムな経路修正: NavMeshAgentは、動的な環境変化に適応する能力を備えています。例えば、障害物が現れた場合や、目的地が変更された場合でも、NavMeshAgentはリアルタイムで経路を修正し、スムーズな移動を維持します。これにより、ゲーム内のキャラクターやAIがより自然な動きを実現できます
スムーズな移動: NavMeshAgentは、アニメーションや移動の滑らかさに関しても優れたパフォーマンスを提供します。経路の計算や移動は、最適なアニメーションと連携して、キャラクターの動きをより自然に見せることができます
3rdPartyAsset:
AsestStoreにはNavMeshAgentと連動するアセットが販売されています。AIのアルゴリズム拡張性を上げるものや、エディタのインターフェースの快適性を向上させるものなど幅広く存在しています
またデメリットとしては以下の事項が考えられます
1.Web上に情報が少ない
基本的な活用方法などはいくつかまとめの記事や公式のyoutubeなどに
動画があったりしますが。少々踏み込んだ内容になると極端に情報が
少なくなります。
ある程度自身で理解を深めるために触る必要性が出るかもしれません
2.RiggidBodyとの互換性は悪い
NavMeshAgentの基本構想として、平面のメッシュ状に移動可能エリアを
設定し、そのうえでの移動を司るシステムとなっております
そのため、物理的に力を加えてジャンプなどの挙動を加えるオブジェクト
に対しては相性が非常に悪いです(使えないわけではない)
物理演算を多用するプロジェクトなどには向かないケースもあります
4.実際に敵キャラをうごかす
実際に現在制作中のゲームにNavMeshAgentを使って、敵キャラクターを動かしていく工程を紹介します
Step1 StageにNavMeshを設定する
まずは、ステージに敵が歩けるエリアを作成しています
ウインドウから「AI」を選択して「Navigation」ウインドウを
表示させます
シーン内のナビゲーションメッシュを「Bake(ベイク)」するエリアを選択します。これは、プレイヤーが移動可能な範囲を示すメッシュを生成する領域です
先ほど「Bake(ベイク)」という言葉を使いましたが
「歩けるエリア」を、「メッシュに焼き付ける(ベイクする)」といった
ニュアンスで覚えてみるといいかと思います
Navigationウインドウの「エージェント」と「エリア」のタブから
移動できるスロープの角度、跨ぐことのできる段差(階段のステップ高さ)などのパラメーターを設定していきます
ステップの高さなどキャラクターのスケールと合わせて設定してください
今回シーン上に簡単なアスレチックを作成しました
「歩けるエリア」のオブジェクトに
スタティックフラグを設定する必要があります
NavigationMeshは動的なオブジェクトにはベイクすることはできません
この状態でナビゲーションのタブより
実際にベイクしてみます
「歩けるエリア」に青いメッシュが表示されていれば成功です
スロープの角度や登れない段差部分等をチェックしてみてください
想定するエリアに
step2.キャラクターにNavMeshAgentをセットする
さてそれでは敵のオブジェクトを作成しましょうカプセルでもなんでも構いませんので
敵のオブジェクトシーン上に配置したら
navmeshagentをアタッチします
今回はついでにアニメーションもアタッチしておきます
NavMeshAgentのパラメーターについてさらっと解説します
Speed (速度):
エージェントの移動速度を表します
NavMeshAgentが目標地点に向かう際の速度を制御します
Acceleration (加速度):
エージェントが目標に向かう際の加速度を表します
この値が高いほど、エージェントはより速く目標地点に到達します
Angular Speed (角速度):
エージェントが方向転換する際の速度を表します
つまり、エージェントが目標地点を向く速度を制御します
角速度が遅いとコーナーにおいて大回りになります
逆に角速度が早ければ小回りになます
Stopping Distance (停止距離):
エージェントが目標地点に到達したとみなすための距離です
この距離に達した時点で、エージェントは目標地点に到達したとみなされます
Auto Braking (自動ブレーキ):
このオプションが有効になっている場合、エージェントは目標地点に近づくにつれて自動的に減速します。
目標地点に近づくと速度がゼロになります
Auto Traverse Off Mesh Link (オフメッシュリンクの自動通過):
このオプションが有効になっている場合、エージェントは自動的にNavMesh上のオフメッシュリンク(通常、ジャンプや登りなどの特別な移動)を通過します。
パラメーターはインスペクター上で編集できます
デザイナーが調整しやすいのも良い点です
では簡単なスクリプトを作成していきます
using UnityEngine;
using UnityEngine.AI;
public class AgentController : MonoBehaviour
{
public Transform target; // プレイヤーの位置
private NavMeshAgent agent;
void Start()
{
agent = GetComponent<NavMeshAgent>();
// ターゲットをプレイヤーに設定
if (target == null)
{
target = GameObject.FindGameObjectWithTag("Player").transform;
}
}
void Update()
{
// ターゲットが存在する場合、その位置へ移動
if (target != null)
{
agent.SetDestination(target.position);
}
}
}
using UnityEngine.AI; を忘れずに
簡単なスクリプトですが解説します
Start()でNavMeshAgentコンポネントを取得とターゲットの位置情報
(今回はプレイヤーのトランスフォーム)の取得
Update()で
agent.SetDestination(target.position);
によりターゲットの位置に移動させます
RiggidBodyに頼らない位置情報の更新なので記述がシンプルです
当然ですが障害物を回避するルートを計算してターゲットの位置までこれで移動させることができます
ただし、これではあまりにそっけないのでアニメーターに速度をわたしてみます
using UnityEngine;
using UnityEngine.AI;
public class AgentController : MonoBehaviour
{
public Transform target; // プレイヤーのTransform
private NavMeshAgent agent;
private Animator animator; // アニメーター
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
// ターゲットをプレイヤーに設定
if (target == null)
{
target = GameObject.FindGameObjectWithTag("Player").transform;
}
}
void Update()
{
// ターゲットが存在する場合、その位置へ移動
if (target != null)
{
agent.SetDestination(target.position);
// 速度をアニメーターに渡す
float speed = agent.velocity.magnitude;
animator.SetFloat("Speed", speed);
}
}
}
これでアニメーターにSpeedの数値を渡すことができます
本記事では最後にプレイヤーに「近づいたら止まる」を実装します
using UnityEngine;
using UnityEngine.AI;
public class AgentController : MonoBehaviour
{
public Transform target; // プレイヤーの位置
private NavMeshAgent agent;
private Animator animator; // アニメーター
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
// ターゲットをプレイヤーに設定
if (target == null)
{
target = GameObject.FindGameObjectWithTag("Player").transform;
}
}
void Update()
{
// ターゲットが存在する場合、その位置へ移動
if (target != null)
{
float distance = Vector3.Distance(transform.position, target.position);
if (distance > agent.stoppingDistance)
{
agent.SetDestination(target.position);
// 速度をアニメーターに渡す
float speed = agent.velocity.magnitude;
animator.SetFloat("Speed", speed);
}
else
{
// 一定の距離に近づいたら停止する
agent.ResetPath();
animator.SetFloat("Speed", 0f);
}
}
}
}
if (distance > agent.stoppingDistance){}
NavMeshAgentのパラメーターのStopping Distance (停止距離)
を直接参照してこの距離にプレイヤーが入った場合にエージェントは移動を停止します
どうでしょうか、実装できたでしょうか?
ここまで理解できればいろいろな挙動にに派生することができます
「止まった後”Attack”トリガーを渡して攻撃する」
「RayCastを利用して視界に入ったら追跡をする」
「指定したルートを巡回する」
「プレイヤーから逃げる」 などなど
これだけでもちょっと楽しいゲーム作れそうな気になりませんか?
最後に今回はNavMeshAgentの実装動画を作成してみました
もし実装に手間取ったらこちらもご覧になってください
ここまで読んでいただきありがとうございます
あなたのゲーム制作の一助になれば幸いです
この記事が気に入ったらサポートをしてみませんか?