徳島ゲーム開発ごっこ 技術ブログ

ゲームを作るために役に立ったり立たなかったりする技術を学んでいきます!

【Unity】NavMeshを学ぶ エリア編

 僕は今NavMeshを勉強しているんだ。
 分からないことばかりだけど、一生懸命頑張って勉強しているよ。
 今回はエリアとコストについて勉強するよ。
 さあ、今日も頑張るぞー。


この記事にはUnity2017.2.0f3を使用しています。

前回を振り返ってみよう

 前回はNavMeshObstacleを使うことで障害物を作成することに成功した。

www.urablog.xyz

巡回してみよう

 今回はNavMeshのエリアとコストについて勉強したい。

docs.unity3d.com

 勉強を始める前に、同じルートを通り続ける挙動を作っておく必要がありそうだ。
 前回作ったスクリプトを改良し、複数の目的地を順番に移動するスクリプトを作成しよう。

using UnityEngine;
using UnityEngine.AI;

[RequireComponent( typeof( NavMeshAgent ) )]
public class ObjectController : MonoBehaviour
{
    [SerializeField]
    private Transform[]     m_targets   = null;
    [SerializeField]
    private float   m_destinationThreshold  = 0.0f;

    private NavMeshAgent    m_navAgent  = null;

    private int m_targetIndex   = 0;

    private Vector3 CurretTargetPosition
    {
        get
        {
            if( m_targets == null || m_targets.Length <= m_targetIndex )
            {
                return Vector3.zero;
            }

            return m_targets[ m_targetIndex ].position;
        }
    }

    private void Start()
    {
        m_navAgent = GetComponent<NavMeshAgent>();
        m_navAgent.destination  = CurretTargetPosition;
    }

    private void Update()
    {
        if( m_navAgent.remainingDistance <= m_destinationThreshold )
        {
            m_targetIndex   = ( m_targetIndex + 1 ) % m_targets.Length;

            m_navAgent.destination = CurretTargetPosition;
        }
    }

} // class ObjectController

f:id:urahimono:20171015074653p:plain

 複数の目標地点を設定できるようにし、それを順番に移動するようにしてみた。
 NavMeshAgentの機能の一つであるAuto Brakingがある。
 これは目標地点を通り過ぎないように、自動でブレーキをかけてくれる機能のようなんだけど、今回の場合は移動し続けていくため、この機能は不要なので無効にしている。

docs.unity3d.com

 まあ、ドキュメントのサンプルスクリプトを真似ただけだけど。
docs.unity3d.com

f:id:urahimono:20171015074718g:plain

 巡回する挙動が出来たようだ。

エリアを作ってみよう

 今回のメイン科目である「エリア」を作っていこう。
 NavMeshには俺の許可なく最初からいくつかのエリアが設定されているようだ。
 ドキュメント曰く、各エリアについては以下のような記述があった。

  • Walkable - は一般的なエリアのタイプです。どのエリアの上を歩くことができることかを指定します。
  • Not Walkable は、ナビゲーションを防止する、一般的なエリアのタイプです。それはそれの上で NavMesh を取得せず、特定のオブジェクトを障害物としてマークしたい場合に便利です。
  • Jump は、すべての auto-generated Off-Mesh Links に割り当てられているエリアのタイプです。

 ここに俺の考えた最強のエリアを追加していこう。

f:id:urahimono:20171015074837p:plain

 「毒」と「電気」という渡りたくないエリアが完成した。
 シーンにもオブジェクトを追加し、このエリアを設定してみる。

f:id:urahimono:20171015074851p:plain

 エリアを追加したNavMeshを焼いて、実行してみる。

f:id:urahimono:20171015074902g:plain

 どうやらこのカプセルには感覚が無いのか感情が無いのか、危険エリアを無視して進んでいく。
 恐ろしい子である。

コスト設定してみよう

 危険エリアだと認識してもらうために、エリアのコスト設定を上げてみる。

f:id:urahimono:20171015075017p:plain

 「Poison」のコストを5に引き上げてみた。
 これならさすがのカプセルも「毒」エリアに入ることを躊躇することだろう。
 早速試してみよう。

f:id:urahimono:20171015075031g:plain
f:id:urahimono:20171015075139p:plain

 見事にカプセルが「毒」エリアを回避して巡回することが確認できた。
 カプセルにもまだ心が残っていたようだ。

追いかける敵を作ってみよう

 先ほどテストして「Poison」のコストを0に戻し、次のテストを行おう。
 そのためには、Playerのオブジェクトをストーキングするオブジェクトが必要になってくる。
 ストーカーの挙動用のスクリプトを作成しよう。

using UnityEngine;
using UnityEngine.AI;

[RequireComponent( typeof( NavMeshAgent ) )]
public class EnemyController : MonoBehaviour
{
    [SerializeField]
    private Transform       m_target    = null;

    private NavMeshAgent    m_navAgent  = null;

    private void Start()
    {
        m_navAgent = GetComponent<NavMeshAgent>();
    }

    private void Update()
    {
        if( m_target != null )
        {
            m_navAgent.destination  = m_target.position;
        }
    }

} // class EnemyController

 スクリプトを簡単で、ただ指定した目標の位置を毎フレーム更新していくだけのものだ。
 ストーカーの執着心をうまく再現したスクリプトだと自負している。

f:id:urahimono:20171015075157p:plain

 このスクリプトを付けたオブジェクトを配置し、早速実行してみよう。

f:id:urahimono:20171015075210g:plain

 うむ、見事なストーキングぶりだ
 この距離は早いところ警察に相談したほうがいいレベルだ。

入れないエリアを作ってみよう

 さて、このストーカーの入れるエリアに制限を設けよう。
 「毒」エリアは一切気にしないが、処罰である「電気」エリアは恐れるようにしてみよう。
 NavMeshAgentArea設定から「電気」エリアを外しておこう。

f:id:urahimono:20171015075323p:plain

 さあ、この状態で実行だ。

f:id:urahimono:20171015075708g:plain
f:id:urahimono:20171015075808p:plain

 「電気」エリアにストーカーが入れないことが確認できた。
 まあ、別ルートを通っても追いかけまわしているところを見る限り、やはり警察に連絡する以外根本的な解決方法はなさそうだ。

今日の勉強終了

 続きました。

www.urablog.xyz