UnityのNavMeshを使ってみた


もう8月も終わりですね。エンジニアのNHです。


さて今回は、Unityの標準機能である「NavMesh」を使った、ナビゲーションシステムを試してみたいと思います。


■NavMeshとは

Unityのナビゲーションシステムとして用意されている、歩行可能面を描写するデータ構造の事です。
このデータ構造を「NavMesh Agent」が解釈し、「NavMesh Obstacle」を回避しながら動くという、一連のナビゲーションを実現する事が出来ます。

経路探索には、有名な「A*」アルゴリズムが使われているようです。
(参考:公式マニュアル


では早速、デモを作ってみたいと思います。


■作るもの

2チーム分エージェントを作成し、
障害物をよけながら、反対側のゴールへ向かわせるデモ


■デモの仕様

以下のような仕様を考えてみました。

  1. エージェントは1チームあたり20名で、計40名。
  2. 各エージェントは、反対側にある、自分と同じ色のゴールを目指す。
  3. 道中には、移動式の障害物を設置する。
  4. エージェントが障害物にあたると、障害物の動きにより進路が変わる。
  5. ゴールに先にたどりついたチームの勝ち(特にクリア判定はなし)



■準備

1. シーンの作成


以下のようなシーンを作成後、NavMeshを「Bake」します。



Hierarchy構造は以下の通りです。




「Player, Enemy」と「Wall」にそれぞれ、「NavMesh Agent」、「NavMesh Obstacle」をアタッチしています。
また、「Wall」には、「Wall」タグをつけており、スクリプト側で判定します。


2. スクリプトの作成とアタッチ


次に、各エージェントに以下のスクリプトをアタッチします。

using UnityEngine;
using System.Collections;

public class NavController : MonoBehaviour
{
 // ゴール: 各エージェントは、自分と同じ色のゴールへ向かいます。
 public Transform Goal;
 
 // NavMeshエージェント
 NavMeshAgent agent;

 // Use this for initialization
 void Start ()
 {
  // エージェント
  agent = GetComponent ();
  agent.destination = Goal.position; 
 }
 
 // Update is called once per frame
 void Update ()
 {
  // agent.destination = goal.position;
 }
}



更に、シーン内にシーン管理用スクリプトを追加します。

using UnityEngine;
using System.Collections;

public class SceneManager : MonoBehaviour {

 // 障害物
 GameObject[] wallObstacles;
 
 // 障害物の移動に関する変数
 int moveCount;
 bool reverse;
 float moveAmount;
 
 const int MOVELIMIT = 300;
 const float MOVEAMOUNT = 0.5f;

 // Use this for initialization
 void Start () {
  // 障害物
  wallObstacles = GameObject.FindGameObjectsWithTag ("Wall");
  reverse = false;
  moveAmount = MOVEAMOUNT;
 }
 
 // Update is called once per frame
 void Update () {
  // A. 障害物の動く方向を反転します。
  if (moveCount >= MOVELIMIT) {
   ToggleDirection (ref reverse, ref moveAmount);
   moveCount = 0;
  }
  // B. 障害物の移動を制御します。
  ObstaclesMove (moveAmount);
 }

 // A. 障害物の動く方向を反転します。
 void ToggleDirection (ref bool flg, ref float amount)
 {
  if (flg) {
   flg = false;
   amount = MOVEAMOUNT;
  } else {
   flg = true;
   amount = -MOVEAMOUNT;
  }
 }
 
 // B. 障害物の移動を制御します。
 void ObstaclesMove (float amount)
 {
  foreach (GameObject wallObstacle in wallObstacles) {
   wallObstacle.transform.Translate (amount, 0f, 0f);
   moveCount++;
  }
 }
}




以上で準備完了です。


では早速動かしてみましょう。


■結果


結果は以下の通りです。



僅差で、青の勝ち!!

赤チームも健闘しました。

Agentたちにとっては、少しかわいそうなコースでしたが、ご覧の通り、
非常に簡単に、簡易群衆シミュレーションを行う事が出来ました

経路の重みづけなど、細かいアレンジ・制御を加える事で、
更にいろんなことができそうなNavMesh。
ガンガン活用できればと思います。


それではごきげんよう。





トンガルマンWebサイト
https://tongullman.co.jp/index.php
facebook
https://www.facebook.com/Tongullman

0 件のコメント:

コメントを投稿