Unityに関連する記事です

 2D ゲームにおける、NavMeshAgent によるベーシックな追跡機能の実装例です。
タイルマップ上でも機能します。

 NavMeshAgentコンポーネントを使用することで、NavMesh上での効率的な移動が実現され、リアルタイムでの対象の追跡が可能になります。



サンプルコード


 NavMeshAgent コンポーネントがアタッチされているゲームオブジェクトに、このスクリプトをアタッチして利用します。
今回は採用していませんが、[RequireComponent(typeof(T))] 属性を付与することで安全に利用できます。

 ゲームオブジェクトをインスタンスして NavMeshAgent による移動を行いたい場合、
事前に NavMeshAgent コンポーネントをオフにしておくか、情報を取得してから経路を設定するようにします。

 インスタンスされた直後は Bake されている経路情報を知らないため、経路検索に失敗してエラーになるためです。


Chaser.cs

 <= クリックすると開きます



解説


 public Transform target で指定されたプレイヤーオブジェクト(または他の対象)を追跡するためのTransformを保持する変数を宣言します。

 private NavMeshAgent agent でNavMeshAgentコンポーネントを保持する変数を宣言します。NavMeshAgentは、NavMesh上での移動を管理するコンポーネントです。

 Start メソッド内で、NavMeshAgentコンポーネントを取得し、移動速度を設定します。
もしNavMeshAgentコンポーネントが取得できなかった場合、エラーメッセージを表示します。

 Update メソッド内で、以下の処理を行います。

   a. NavMeshAgentが存在しないか、対象(プレイヤーオブジェクト)が設定されていない場合、処理を中断します。これはエラーを防ぐためのチェックです。

   b. オブジェクトと対象までの距離を計算し、デバッグログで表示します。この距離をもとに、対象が視界に入ったかどうかを判定します。

   c. sightRange 変数は視界を表現します。
    この内に対象がいる場合(距離が sightRange 以下の場合)、NavMeshAgentの SetDestination メソッドを使用して対象の位置を移動目標地点に設定します。
    これにより、オブジェクトは対象を追跡します。

   d. sightRange よりも対象が遠くにいる場合、NavMeshAgentの ResetPath メソッドを使用して移動を停止します。つまり、対象が視界外に出たと判断して、追跡を停止します。



 3Dの場合と大きく異なるのは、agent.updateRotation と agent.updateUpAxis をオフに設定し、3D用の回転設定を無効にしている部分です。
また高さの情報も不要であるため、Y 軸は常にプレイヤーの情報を利用し、上下左右方向の対象までの距離を計算しています。
(分かりにくいですが、NavMeshAgent は3D空間を認識しているため、上下左右の情報は X 軸と Z 軸になります。)

 これにより、2D空間でNavMeshを正しく使用できます。


修正案 ー目標を失った場合に、初期地点まで戻っていく機能の追加ー


 目標を失った場合に、初期地点まで戻っていく機能を追加してみましょう。


Chaser.cs

 <= クリックすると開きます



<ポイント>


 Update メソッド内の処理が、適切な位置で return され、不要な処理が動かないように制御されています。
このような形で return を上手く活用すると、if 文によるネストを浅く出来ます。

 仮に、もしも追跡中だったら、という if 文で処理を書く形を見てみましょう。


     private void Update()
    {
        // NavMeshAgent が取得できない、あるいは移動先の対象が設定されていない場合
        if (!agent || !target)
        {
            // 処理を行わない(エラーが出てしまうため)
            return;
        }

        // このオブジェクトと移動先の対象までの距離を計算
        Vector3 targetPosition = new Vector3(target.position.x, transform.position.y, target.position.z);
        float distanceToPlayer = Vector3.Distance(transform.position, targetPosition);

        // どの位離れているかを表示
        Debug.Log("対象までの距離 : " + distanceToPlayer);

        if (isChasing)
        {
            // 対象が視界に入った場合(距離が近い場合)
            if (distanceToPlayer <= sightRange)
            {
                // 対象の位置を移動目標地点に設定
                // Update メソッド内で実行しているので、対象が移動すると、目標地点も更新されるので追跡する
                agent.SetDestination(targetPosition);
            }
            else
            {
                // 対象が視界外の場合(距離が遠い場合)、スタート地点に戻る
                agent.SetDestination(originalDestination);
            }
        }
        else
        {
            // 追跡中ではない場合、移動を停止する
            agent.ResetPath();
        }
    }

 追跡するか、否かを判断する前に計算処理をしていたり、if 文内にさらに if 文を作って追跡時の処理を書いているので、
if 文のネストが深く、また範囲が広く読みにくくなっています。

 分岐処理を作成する場合には、true であったときに処理を動かした方がよいのか、false として処理を止めるようにした方がよいのか
両方の視点を持って作っていくように心がけましょう。
 
 コーディングスキルを上達させるコツの1つです。
このような視点を手に入れられないと、いつまでも同じ形式の分岐処理しか作れないため、スキルアップに繋がりません。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます