Categories: Unity

Unity:NavMesh Agentを使ってキャラクターを自動巡回させる

今回はUnityの公式マニュアルに掲載されている方法を使ってキャラクターを自動巡回する手順を試してみたいと思います。

Unityの公式マニュアル、エージェントに設定した地点を巡回させる – Unity マニュアル を見ると、Unityのナビゲーションシステムについて次のように書かれています。

NPC が、ある種の順序で通過したり立ち寄ったりするために役に立つ、いくつかのキーとなる地点を設けることによって、より納得のいく巡回パターンを設定することができます。例えば、迷路では、交差点と曲がり角に巡回のキーとなる地点を置き、エージェントがそこですべての通路を確認するようにできます。

というわけで、さっそくシーンを作成してみましょう。

シーンとキャラクターのセットアップ

シーンのセットアップ

今回のシーンはこちらの記事を参考に基本オブジェクトを組み合わせてこんな感じに。ライティングはエリアライトと自己発光マテリアルのみ。キャラクターのライティングのためにライトプローブを配置しています。

キャラクターのセットアップ

NPCのキャラクターはUnityの無料アセットのキャラクター Space Robot Kyle を使用します。

Animator Controller の作成までの手順はこちらの記事を参考に進めます。

次に NavMesh Agant コンポーネントを追加します。シーンに配置したキャラクター”Robot Kyle”を選択。[Inspector]ウィンドウ > [Add Component]ボタン > Navigation > Nav Mesh Agant を選択。[Scene]ウィンドウを見るとキャラクターに緑色のラインの円柱が表示されています。

スクリプトの作成と編集

スクリプトの作成

自動巡回のスクリプトを作成します。キャラクターを選択。[Inspector]ウィンドウ > [Add Component]ボタン > New Script を選択。NameフィールドにPatrol と入力して[Create and Add]ボタンをクリック。

スクリプトの編集

Unityの公式マニュアル、エージェントに設定した地点を巡回させる – Unity マニュアル にスクリプトコードが掲載されているのでまずはコピペして内容を確認しながらコメントを書いてみました。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// "NavMeshAgent"関連クラスを使用できるようにする
using UnityEngine.AI;

public class Patrol : MonoBehaviour
{
    // 巡回地点オブジェクトを格納する配列
    public Transform[] points;
    // 巡回地点のオブジェクト数(初期値=0)
    private int destPoint = 0;
    // NavMesh Agent コンポーネントを格納する変数
    private NavMeshAgent agent;

    // ゲームスタート時の処理
    void Start()
    {
        // 変数"agent"に NavMesh Agent コンポーネントを格納
        agent = GetComponent<NavMeshAgent>();
        // 巡回地点間の移動を継続させるために自動ブレーキを無効化
        //(エージェントは目的地点に近づいても減速しない)
        agent.autoBraking = false;
        // 次の巡回地点の処理を実行
        GotoNextPoint();
    }

    // 次の巡回地点を設定する処理
    void GotoNextPoint()
    {
        // 巡回地点が設定されていなければ
        if (points.Length == 0)
            // 処理を返します
            return;
        // 現在選択されている配列の座標を巡回地点の座標に代入
        agent.destination = points[destPoint].position;
        // 配列の中から次の巡回地点を選択(必要に応じて繰り返し)
        destPoint = (destPoint + 1) % points.Length;
    }

    // ゲーム実行中の繰り返し処理
    void Update()
    {
        // エージェントが現在の巡回地点に到達したら
        if (!agent.pathPending && agent.remainingDistance < 0.5f)
            // 次の巡回地点を設定する処理を実行
            GotoNextPoint();
    }
}

完成したスクリプトコンポーネントを[Inspector]ウィンドウで見るとこのようになっています。

巡回地点のセットアップ

巡回地点オブジェクトの作成

シーンに巡回地点のオブジェクトを配置します。[Hierarchy]ウィンドウ > [Create]ボタン > Create Empty を選択。名前を”DestPoint_0″に変更。オブジェクトを3つ複製して合計4つの巡回地点オブジェクトを作成します。

それぞれの配置座標は下記のようにしました。

  • DestPoint_0: X-2 / Y0 / Z-1.5
  • DestPoint_1: X-2 / Y0 / Z2
  • DestPoint_2: X2 / Y0 / Z2
  • DestPoint_3: X / Y0 / Z

巡回地点の設定

作成した巡回地点をスクリプト”Patrol”コンポーネントに登録します。キャラクターを選択。[Inspector]ウィンドウ > Patrol (Script) コンポーネント > Points をクリック。配列数フィールドに4を入力。配列オブジェクトを格納するフィールドが表示されたら、それぞれの巡回地点オブジェクトをドラッグ&ドロップで割り当てます。

ナビメッシュのベイク

最後に、NavMesh Agent が巡回するエリアのナビメッシュのベイクをしましょう。メニュー:Window > Navigation を選択。[Navigation]ウィンドウ > [Bake]ボタンをクリック。さらにそのまま[Bake]ボタンをクリック。

ナビメッシュのベイクが終わると[Scene]ウィンドウで水色のナビメッシュが表示されます。

巡回動作の調整

まずは動作確認してみましょう。なんだか勢いよく巡回地点を移動しているので、パラメータを調整する必要があります。

公式マニュアルの “NavMesh Agent を他のコンポーネントと共に使う” に次の記載がありました。

NavMesh Agent と Root Motion を持つ Animator は競合を引き起こす場合があります。毎フレーム、両コンポーネントがトランスフォームを動かそうと試みるためです。

というわけで、Animator コンポーネントの設定を変更します。キャラクターを選択。[Inspector]ウィンドウ > Animator コンポーネント > Apply Root Motion のチェックを外します。

それから、アニメーションの再生速度を少し遅くしました。[Animator]ウィンドウ > アニメーションノードを選択。[Inspector]ウィンドウ > Speed 0.6 に変更。

NavMesh Agent (Script)コンポーネント のパラメータは色々試した結果このように調整しました。

WebGLでビルド

今回の内容をWebGLでビルドしました(ダウンロードサイズ:約16MB)
マウス左ドラッグで視点を移動できます。

corevale