皆さんこんにちは。HTGです。
今回は工大祭の展示物とそれに使ったUnityのある機能についてお話させていただきます。
今年も自作ゲームを展示していました。

20151026-01

タイトルは「GetCoin!」
名前の通りコインを集めることが目的で、人型にならなかった箱型のキャラクターを操作して攻撃能力を持てなかったうろついているだけの敵キャラ(カマキリ)を倒し、落としたコインを拾い集めていくゲームです。
20151026-02

僕の中では正直言って完成度低いです。本来やりたかったものからルール大幅変更してるし。
ぶっちゃけ何とかトゥーンを遊びすぎて作るのサボってました。みんなもほどほどにね!

さて、実際にプレイしないとわかってもらえないことですが、この敵キャラのカマキリ、段差あり高低差ありのステージを割とフリーダムに動き回ります。たまに渋滞とか壁に引っかかるとかするけど
この挙動を普通にプログラムで作ろうとすると非常に難しいので短時間で作るのは不可能です(個人の感想です)が、これを簡単な手順で可能にしてくれたのがUnityのとある機能です。
ここからが本編です
Unityの持つナビゲーション機能ならば、指定の場所に向かって歩くオブジェクトを簡単に作れます。
この辺の話は大体Unityマニュアルにあるので、実際に使いたい人はそちらの方がオススメです。
Unity - マニュアル: ナビゲーションと経路探索

それでは、指定の場所に向かって歩くオブジェクトができるまでを紹介しましょう。

1.NavMeshをつくる
まずは、オブジェクトが歩ける地面を定義しますが、その前にその地面となるオブジェクトを用意します。
20151026-03
ちなみに、奥に見える赤いポールはゴールの場所を示すためのオブジェクトです。

次に、この地面オブジェクトを選択した状態で「Window->Navigation」と選び、出てきたウインドウで「Navigation Static」にチェックを入れてから右下の「Bake」をクリックします。
20151026-04

20151026-05
するとこのように、地面に相当する部分が水色になりました。(見えやすくするために一時的に地面の色を白に変更しています)
この水色の部分が地面として定義された場所、NavMeshとなります。
逆に言えば水色になってない部分は通れないものとみなされるので、予定と違うところは自力で調整して再度Bakeしましょう。

2.歩くオブジェクトを作る
地面ができたら次は歩くキャラが必要ですね。
Unityは各オブジェクトにコンポーネントを追加することでオブジェクトに機能を追加しますが、歩くキャラには「NavMeshAgent」を追加します。
移動や回転の最高速度、オブジェクトの大きさなどのパラメーターを調整して、スクリプトで目的地を指定すれば、あとは勝手に移動してくれます。

ちなみにそのスクリプトの内容はこちら

using UnityEngine;
using System.Collections;
public class Cube : MonoBehaviour {
    [SerializeField]
    GameObject goal;
    [SerializeField]
    NavMeshAgent agent;
    void Start () {
        agent.destination = goal.transform.position;
    }
}


慣れない人が見ると一見難しそうですが、実はやってることは次の3つだけ。単純です。
「ゴールオブジェクトのフィールド宣言(中身はUnity上で指定できる)」
「NavMeshAgentのコンポーネントのフィールド宣言(Unity上で自分自身のものを指定する)」
「NavMeshAgentの目的地をゴールオブジェクトの座標にセットする」

そしてこの移動時の向き変更の処理も自動でやってくれます!すごい!
ですが、回転速度(AngularSpeed)が低いと振り向き時に後ろ歩きやカニ歩きをするので
AngularSpeedは360にするのが個人的オススメ。
ちなみに、何らかの理由(道がない、NavMesh上ではない等)で目的地にたどり着けない場合は、
そこに最も近い場所まで移動するようになってます。つまり目的地設定がメチャクチャでもOK

3.障害物を作る
さて、こうしてできた歩くオブジェクトですが、このままだと不便なことがあります。
試しにブロックで道を塞いでやりましょう
20151026-06

すり抜けました。全く塞げてませんでした。

残念ながら、NavMeshAgentはこのブロックを障害物と認識していないのでこうなってしまいます。
(ちなみに、NavMeshAgent同士はちゃんとぶつかります。設定次第では片方にもう片方を避けさせることもできます)

というわけで認識させます。

NavMashObstacleコンポーネントを追加すれば、そのオブジェクトを障害物と認識して先に進めなくなります。
さらにコンポーネントのCurveにチェックを入れると、そこは通れないから別の道を使おうということまで考えてくれます。
これを動画で見せられないのが残念ですが、Unityを持っている人なら実際にやってみると面白いかもしれません。

4.Off-MeshLink
このナビゲーション機能にはできないことがいくつかあります。
その中でも大きいのが、ジャンプができないということです。
つまりちょっと離れた足場も、坂道がない段差もたどり着けません。
せいぜい床の端あたりでぼんやり目的地を眺めてるだけです。
それを解決するのが、Off-MeshLinkというコンポーネントです。
Off-MeshLinkコンポーネントは、始点と終点(双方向にすることも可能)になるオブジェクトを指定することで、その間を道としてつなぐことができます。端的に言うとNavMeshにおけるワープポイントになります。
ただし、始点から終点への移動は直線的になる(もちろん他オブジェクトはすり抜ける)ため、そのまま使用した場合の見栄えは微妙です。
これを改善するには自力で挙動を設定する必要があります。

最後にナビゲーション機能の利点と不利点を自分なりにまとめてみました。
なお、不利点はナビゲーション単体で使用した場合に限るため、他のコンポーネントやスクリプト次第では克服可能です。

○利点
・移動処理が簡単に作れる!
・方向転換の処理も自動!
・道がつながっていれば建物の一階から屋上へ移動ということも可能!
・目的地を毎フレーム更新すれば何かをひたすら追いかけることも可能!
○不利点
・空中は無理(せいぜい見えない足場が限度)
・動く足場も無理(NavMeshはbakeした時の形状で固定されているようです)
・NavMeshAgentが有効な時は強制的にNavMesh上に着地させられる(着地できるNavMeshがないとエラーを吐く)
・Off-MeshLinkをそのまま使うと直線移動になる

Unityを使ってる皆さんもこれから始めようとする皆さんも、ぜひこの機能を利用してみてください!
便利です、はい。