テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】NavMeshComponentsに2D対応ブランチが追加されていたので試してみた

https://user-images.githubusercontent.com/1644563/68397953-e4cd2700-016b-11ea-913b-f062f47bc505.gif

NavMeshComponents

 NavMeshComponentsはNavMeshの機能を拡張するクラス郡です。NavMeshを動的に構築したりアセットに書き出したりといった事を非常に簡単に実現してくれます。エディターからリンクを参照される程度には重要な機能の割にパッケージ化されない謎機能でもあります。

2D ブランチ

 なんとなくブランチ一覧を見た時「2019.3-2D」という妙なブランチを見かけたので早速入れて試した所、Tilemapで作った地形をNavMeshで走らせることが出来ました。追加されているのはNavMeshBuilder2DNavMeshSourceTag2D というクラスで、この機能でナビゲーションを実現します。

f:id:tsubaki_t1:20191107234235j:plain
ブランチ

f:id:tsubaki_t1:20191107234203j:plain
含まれるスクリプト

タイルマップでNavMeshを使用しよう

 タイルマップベースでパスの取得を試してみました。

f:id:tsubaki_t1:20191110171319j:plain

ステージを作成しよう

 まずはタイルマップベースのステージを作成します。使用したのは2D UFO Tutorialです。この中のBackGround.pngに用が合ったので使用しています。現実的な話で言えば、タイルマップなら別に何でも良いです。取得した画像ファイルはタイルのグリッドに合わせて分割します。今回の場合は3x3で9分割です。
 なおスプライトのサイズが大きすぎるかもしれないので、Pixel Per Unitを1000辺りにしました(1000ピクセルが1m)

assetstore.unity.com

f:id:tsubaki_t1:20191110172017j:plain
Background.pngを9分割

 次にCustom Physics Shapeを選択して、タイルのコライダーの形状を変更します。このコライダーは通れる場所に設定するという点に注意する必要があります。通常だと逆(コライダーが無い場所を通れる)ですが、今回の場合はそうなっています。

f:id:tsubaki_t1:20191110172449g:plain
コライダーの設定

 あとはタイルマップを作成していきます。

  1. パレットを作成
  2. パレットにタイルを登録
  3. タイルを作成していく

あとは作成したタイルマップにはTilemap Collider2Dを設定します。これで事前準備は完了です。

https://user-images.githubusercontent.com/1644563/68541238-d6158880-0394-11ea-838f-cc700df166c2.gif

f:id:tsubaki_t1:20191110173535j:plain

NavMeshをベイクしよう!

 NavMeshをベイクします。

 最初に先程作成したTilemap Collider 2Dが付いているグリッドに NavMesh Surface Tag 2D を設定します。 GameObjectを新しく作成し、NavMeshBuilder2Dコンポーネントを追加します。 NavMeshBuilder2DのBakeボタンを押します。

f:id:tsubaki_t1:20191110174103j:plain

f:id:tsubaki_t1:20191110174143j:plain

 実際にベイクできたかは Window > AI > Navigation ウィンドウを開いて確認します。ベイクで来ている場合は移動範囲を青く表現されます。
 ベイクで来たらBake On Enableを設定しておきます。

f:id:tsubaki_t1:20191110174210j:plain

移動範囲を、もっとタイルに沿って配置したい場合は、Agent TypeのHumanoidのRadiusを小さな値にします。

NavMeshによる移動経路を取得しよう

 ナビゲーションの移動経路を取得してみます。これは特に特殊なことはせず、今まで通りの形で取得できます。例えばパスを LineRenderer で表現するコードを考えてみます。

using UnityEngine;
using UnityEngine.AI;

[DefaultExecutionOrder(10)]
public class DrawPath : MonoBehaviour
{
    [SerializeField] LineRenderer line;

    [SerializeField] Transform startPos, endPos;

    private NavMeshPath path;

    void Awake()
    {
        path = new NavMeshPath();
    }

    void OnEnable()
    {
        var result = NavMesh.CalculatePath(startPos.position, endPos.position, NavMesh.AllAreas, path);
        enabled = line.enabled = result;

        if( result )
        {
            var corners = path.corners;
            line.positionCount = corners.Length;
            line.SetPositions(corners);
        }
    }
}

f:id:tsubaki_t1:20191110180406j:plain

f:id:tsubaki_t1:20191110180417j:plain

NavMeshAgentを使用する場合

 NavMeshAgentはパスを3Dの物と認識しているので注意が必要です。NavMeshAgentを使用したい場合、座標だけ同期して実際の描画は別のGameObjectで行う等が楽で良いです。

関連

 トップ絵のキャラクターの表現はコレを使用。移動方向を渡せば良いだけの簡単仕様

tsubakit1.hateblo.jp

 この機能はすごく単純に、NavMeshをベイクする際のポリゴン情報をNavMeshから取得しているだけです。

tsubakit1.hateblo.jp