UnityのNavMeshComponentsアセットの使い方とゲーム中にNavMeshのベイクをする

今回はUnityのナビゲーション機能でゲーム実行中にナビメッシュをベイクしてみたいと思います。

ナビゲーション機能については

Unityのナビゲーション機能を使って敵キャラクターを移動させます。ナビゲーション機能はあらかじめBakeされたフィールドを移動出来る機能です。

や「ナビゲーション機能」カテゴリの中にもいくつか記事があるのでそちらを参照してください。

ゲーム実行中にナビメッシュが出来ると、イベントをクリアしたら別のフィールドへの道が表示され、そのフィールドを動的にナビメッシュしてNavMeshAgentで移動させる事が出来ます。

スポンサーリンク

NavMeshComponentsアセットのインポート

動的なナビメッシュをする為にはNavMeshComponentsというアセットが必要ですが、NavMeshComponentsアセットは追加アセットなので

NavMeshComponents - High Level API Components for Runtime NavMesh Building

↑からZIPファイル等でダウンロードしてください。

ZIPファイルをダウンロードした人はファイルを解凍し、フォルダの階層を辿ってNavMesComponentsフォルダをUnityのAssetsフォルダにドラッグ&ドロップします。

これで準備が出来ました。

ナビゲーション機能が新しくなってる!?

ついこの間までUnity5.3.4f1だったものでUnity2017にしたらナビゲーションのインスペクタが変わっていますね。

そこで、Navigationウインドウについて少し見ていきます。

NavigationウインドウのAgentsタブを選択すると、

NavigationのAgentsタブ

↑のようにAgent Typesを追加する事が出来ます。

Agent TypeはNavMeshAgentで選択する事が出来、エージェントのタイプによってベイクするナビメッシュを変更できます。

BakeタブではNavigation Staticにチェックを入れたゲームオブジェクトのベイクがされますが、Agent Type毎にベイクを分ける事は出来ないようです。

NavigationウインドウのBakeタブ

NavMeshComponentsアセットのNavMeshSurfaceコンポーネントを使うとAgent Typeに合わせたベイクが出来ます。

NavMeshSurface

NavMeshSurfaceコンポーネントを使うと指定したAgent Typeのナビメッシュをベイクする事が出来ます。

NavMeshSurfaceはUnityメニューのGameObject→AI→NavMesh Surfaceを選択して作成するか、空のゲームオブジェクト等を作成しインスペクタのAdd ComponentからNavigation→NavMeshSurfaceを取り付けます。

今回は空のゲームオブジェクトを作成し、名前をNavMesh Surfaceという名前にし2つのNavMeshSurfaceコンポーネントを取り付けます。

2つ取り付けるのはAgent Type毎にナビメッシュをベイクする為です。

あらかじめNavigationウインドウでAgent Typeを2つ作っておきます。

NavMeshSurfaceコンポーネントのインスペクタ

NavMeshSurfaceの項目を見ていきます。

Agent Typeはエージェントのタイプ。
Collect Objectはベイクする対象のゲームオブジェクトを指定します。

Allはヒエラルキー上の全てのゲームオブジェクト
Volumeはコライダのような範囲を設定し、その中にあるゲームオブジェクト
ChildrenはNavMeshSurfaceが取り付けられたゲームオブジェクトの子要素のゲームオブジェクト

になります。

Include Layersはナビメッシュに含めるレイヤーの指定です。
Use GeometoryでRender Meshesはメッシュ、Physics Collidersはコライダをベイクします。
Default Areaはデフォルトのナビメッシュのエリアを指定します(例えばJumpを指定すると通常のナビメッシュエリアがJumpになりコストが上がります)。

設定としてはこんな感じで、先ほどの画像のような設定をしておきます。

Agent TypeをHumanoidにしたものはCollect ObjectsがChildrenなので、NavMeshSurfaceのベイクをすると子要素のゲームオブジェクトを使ってナビメッシュを作成します。
Agent typeをMonsterにしたものはCollect ObjectsがAllなので、NavMeshSurfaceのベイクをするとヒエラルキー上の全てのゲームオブジェクトを使ってナビメッシュを作成します。

どちらもStaticにチェックを入れなくてもベイクが出来ます。

次にNavMesh Surfaceゲームオブジェクトの子要素にいくつか3D Objectを配置し、Scale等を変更します。

NavMesh Surfaceゲームオブジェクトの子要素にゲームオブジェクトを配置

実際に配置したゲームオブジェクトは

NavMesh Surfaceゲームオブジェクトの子要素のゲームオブジェクト達

↑のような感じになります(キャラクターは関係ありません)。

NavMeshModifier

左上のCubeで階段のような物を作っていますが、上の階のゲームオブジェクトにAdd ComponentからNavigation→NavMeshModifierを取り付けます。

NavMeshModifierを取り付ける

NavMeshModifierコンポーネントはナビメッシュする時のこのゲームオブジェクトの動作を設定する事が出来ます。

Ignore Buildにチェックを入れるとベイクされません。
Override Areaにチェックを入れると、このゲームオブジェクトのArea Typeを上書き出来ます。
Affected Agentsは影響を及ぼすエージェントの指定です。

NavMeshModifierVolume

下の階のゲームオブジェクトにAdd ComponentからNavigation→NavMeshModifierVolumeを取り付けます。

NavMeshModifierVolumeを取り付ける

NavMeshModifierVolumeは範囲を指定してエリアを設定できます。

これで個別のゲームオブジェクトのエリア設定が出来たので、NavMesh SurfaceゲームオブジェクトのNavMeshSurfaceコンポーネントでAgent TypeがHumanoidのもののBakeボタンを押してベイクしてみます。

NavMeshSurfaceでナビメッシュをベイクした状態

↑のように階段のようにしたCubeのエリアが変わっているのがわかります。

NavMeshLink

次はNavMeshLinkコンポーネントについて見ていきましょう。

空のゲームオブジェクトを作成し、名前をNavMeshLinkとします。

NavMeshLinkの子要素にCubeを作成し、Scaleを変更して今いるフィールドと少し離れた場所に移動させます。

NavMeshLinkゲームオブジェクトの階層

NavMeshLinkにはAdd ComponentからNavigation→NavMeshSurfaceを取り付けCollect ObjectsをChildrenに変更して、Bakeボタンを押します。

NavMeshLinkゲームオブジェクトにNavMeshSurfaceを取り付ける

ベイクすると、

別のフィールドとして離して設置する

↑のように今いるフィールドと少し離れたところにNavMeshLinkゲームオブジェクトがあり、ナビメッシュがベイクされています。

このままの状態だと今いるフィールドからNavMeshLinkゲームオブジェクトのフィールドに移動出来ません。

別々にベイクされたナビメッシュを移動出来るようにするのがNavMeshLinkコンポーネントです。

NavMeshLinkゲームオブジェクトのインスペクタでAdd ComponentからNavigation→NavMeshLinkコンポーネントを取り付けます。

Bidirectionalにチェックを入れると相互に移動出来ます。

チェックを入れないとスタート位置からエンド位置の方向のみ移動出来ます。

ここら辺はオフメッシュリンクと同じですね。

シーンビューに茶色い四角が表示されます。

これがスタート位置とエンド位置でクリックするとそれを移動させる事が出来るので、今のフィールドとNavMeshLinkゲームオブジェクトのフィールドを繋げるように移動させます。

NavMeshLinkのスタート地点とエンド地点が四角で表示される

位置の移動はNavMeshLinkコンポーネントで数値を指定する事でも出来ます。

インスペクタでスタート位置とエンド位置を指定することも可能

うまく配置すると

NavMeshLinkで地面が繋がれた

↑のようにフィールドとフィールドが繋がります。

同じフィールドではOffMeshLinkで繋がりますが、別のナビメッシュを繋ぐにはNavMeshLinkを使うという感じですね。

ただこのままだと1点と1点が繋がっているだけなので幅を持たせたいと思います。

NavMeshLinkコンポーネントのWidthの値を増やすと、スタート位置とエンド位置に幅が出来、移動出来る範囲が広がります。

NavMeshLinkの幅が広がった

キャラクターを動かしてフィールドを移動させてみる

キャラクターにNavMeshAgentを取り付け、移動スクリプトを取り付けてフィールドを渡れるかどうか試してみます。

今回はマウスクリックした位置にキャラクターを動かすようにします。

詳しくは

Unityでキャラクターはナビゲーション機能で移動させるが、移動先の指定はマウスクリックで行えるようにします。ナビゲーション機能を使っているので障害物を避けて最適な経路で目的地に進んでくれます。

を参照してください。

スクリプトは

を使います。

移動出来る地面にはFieldという名前のレイヤーを設定しておく必要があります。

試してみると

↑のような感じで移動が出来ました。

動的にナビメッシュしたサンプルの作成

NavMeshComponentsについて見てきました。

これらを使って動的にナビメッシュをベイクしてみましょう。

動的にナビメッシュをベイクというのは実はNavMeshSurfaceの命令で簡単に出来てしまいます。

NavMeshSurfaceコンポーネントの参照をnavMeshSurfaceに入れていたとすると、

と、動的にナビメッシュしたい箇所に記述するだけです。

簡単ですね(^^)/

ほんと、動的にナビメッシュする方法は数行で解説終わりですよ・・・・(‘◇’)ゞ

これだけだとあれなんで・・・・、動的にナビメッシュするサンプルを作成してみたいと思います。

概要としては今のフィールドから別のフィールド近くに移動すると別のフィールドから徐々に道が伸びてきて、伸びきったら動的にナビメッシュをベイクし、キャラクターが別のフィールドに行けるようになる。

という感じのものを作りたいと思います。

別のフィールドを作成

まずは空のゲームオブジェクトを作り、名前をAnother NavMesh Surfaceとします。

別のフィールドのヒエラルキーを作成

Another NavMesh SurfaceゲームオブジェクトにはNavMeshSurfaceとNavMeshLinkコンポーネントを取り付けます。

Another NavMesh Surfaceゲームオブジェクトのインスペクタ

NavMeshLinkのStart PointとEnd Pointはこの後作成する道と今のフィールドの辺りに移動させます。

Another NavMesh Surfaceの子要素に空のゲームオブジェクトを作成し、名前をRoadとします。

RoadにはShowTheWayスクリプトを作成し取り付けます。

RoadにShowTheWayスクリプトを取り付ける

Showメソッドが呼ばれたらコルーチンを使ってRoadゲームオブジェクトの子要素のゲームオブジェクトを順番にアクティブにし、それが終わったら動的にナビメッシュをベイクします。

Roadの子要素にはCubeを3つ作成し、順番に別のフィールドの方から並べます。

階層の順番が肝心でRoadの子要素の1番目が別のフィールドと接触し、子要素の3番目が今のフィールドと接触する位置に配置します。

実際に出来たのが、

出来たフィールドと道

↑のような別のフィールドと道です。

Roadの子要素のCube達はキャラクターが近づくまでは表示させないのでインスペクタの名前の横のチェックを外し非アクティブにしておきます。

Another NavMesh Surfaceゲームオブジェクトに取り付けたShowTheWayスクリプトのShowメソッドは、キャラクターが今のフィールドにある検知エリアに侵入した時に実行するようにします。

今のフィールドにキャラクターの検知エリアを作成する

NavMesh Surfaceゲームオブジェクトの子要素にCubeを作成し名前をShowRoadAreaとしてScaleを調整して検知範囲として使います。

Box ColliderのIs Triggerにチェックを入れ物理的に当たらないようにします。

ここで、移動出来る地面はFieldレイヤーを設定するとしましたが、ShowRoadAreaはただの検知範囲として使います。

ShowRoadAreaのレイヤーはデフォルトのdefaultレイヤーのままにしておきます。

NavMesh SurfaceゲームオブジェクトのAgent TypeがHumanoidのNavMeshSurfaceコンポーネントのInclude Layersでdefaultのチェックを外し、defaultレイヤーが設定されたゲームオブジェクトはナビメッシュの対象外にしておきます。

ナビメッシュする対象のレイヤーからdefaultを外す

これでShowRoadAreaはナビメッシュの対象から外れました。

ShowRoadAreaにはShowRoadAreaスクリプトを取り付けます。

キャラクターにはPlayerタグを設定しておき、キャラクターを検知したらShowTheWayスクリプトのShowメソッドを実行します。

検知エリアにShowRoadAreaスクリプトを取り付ける

検知エリアでキャラクターを検知するにはキャラクターにCharacterControllerコンポーネントが付いているか、コライダ+Rigidbodyが付いている必要があります。

そこでキャラクターにRigidbodyとCapsuleColliderを取り付けておきます。

キャラクターを検知出来るようにRigidbodyとCapsuleColliderを取り付ける

RigidbodyのIsKinematicにチェックとCapsuleColliderのIsTriggerにチェックを入れます。

これで機能が完成しました。

動的なナビメッシュ機能のサンプルの確認

機能が出来たので動的なナビメッシュのベイクが出来るかどうかと道が徐々に表示されるかどうかを確認してみます。

↑のようになりました。

シーンビューの方で道が繋がった後でナビメッシュがベイクされているのがわかりますね。

参考サイト

Introduction and Navigation Overview

スポンサーリンク

記事をシェアして頂ける方はこちら

フォローして頂くとやる気が出ます