NavMesh の AgentTypeID が直観的じゃない件について


Unity で利用できる NavMesh では、異なるパラメータを持つ Agent を作成できます。Inspector で AgentType が選択できるときは、分かりやすい名前で表示されるのですが、スクリプト内では AgentType は名前では指定できず、その代わりに AgentTypeID を利用する必要があります。この AgentTypeID が少しトリッキーで躓いたので、その腹いせに記事を書きます。

問題点

ことは NavMesh の公式拡張である NavMeshComponents のサンプルを触っていたときに起こりました。
Examples/Scenes/5_sliding_window_terrain というシーンは、 NavMeshBuilder クラスを使うことで Agent の周囲にランタイムに動的に NavMesh を作成できる例を示していたのですが、 AgentType が Humanoid の Agent しか存在しなかったので、ここに新しい AgentType を追加したらどうなるんだろうという気持ちになり、試してみることにしました。

AgentTypes は見た目的にすごく Enum 然としています。実際デフォルトで設定されている Humanoid という AgentType に対応する ID は 0 でした。

Examples/Scripts/LocalNavMeshBuilder.cs
// 60行目
var defaultBuildSettings = NavMesh.GetSettingsByID(0);

なので、Humanoid の下にある Ogre に対応する ID は一つインクリメントされて 1 になるものだと思いますよね。そこで、上述のスクリプトの ID を 1 に書き換えて、シーン内の Agent を Orge に設定したのですが、 Failed to create agent because it is not close enough to the NavMesh という警告が出て正常に動作しませんでした。

調べてみた結果、どうやら Ogre に対応する NavMesh が正しく作成されていないことが分かり、 Ogre に対応する AgentTypeID が 1 じゃないのかも、と気づきました。

対応する AgentTypeID の取得方法

色々試してみたのですが、最終的に以下の方法で AgentType に対応する ID が分かります。辞書型に保存することで、AgentType の名前からいつでも ID が取得できるようにしました。
(回りくどい書き方になっているのはちょうどいい API がなかったからです)

Dictionary<string, int> agentTypeIdDict = new private Dictionary<string, int>(); 
for (var i = 0; i < NavMesh.GetSettingsCount(); i++)
{
    var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
    var name = NavMesh.GetSettingsNameFromID(id);
    agentTypeIdDict.Add(name, id);
}

ここで取得できた ID を指定したところ、警告が消え、 Ogre Agent も正しく動作しました。

最後に

結果的に自分の環境では、 Ogre に対応する ID は -1372625422 でした!全然予想と違いましたね!!!!!