Categories: Unity

UnityでNavMeshAgantを使ってマウスクリック位置にエフェクト表示してキャラクターを移動させる

プレイヤーキャラクターをマウスクリックした位置に移動させる

今回は NavMesh 機能の勉強として、マウスクリックでエフェクト表示した場所にプレイヤーキャラクターを移動させる方法を試してみました。

シーンの作成

今回のシーンは Unity公式アセットのモデリングツール ProBuilder を使用し、10m四方で1mの高低差のあるステージを作成しました。
ProBuilder

キャラクターの作成

プレイヤーキャラクターはフリーアセットのキャラクター、Space Robot Kyle を使用します。

キャラクターの制御は Standard Assets の Character アセットをインポートし、ThirdPersonCharacter のコンポーネントを使用します。

まず、メニュー:Assets > Import Package > Charactersを選択。アセットファイルがインポートできたら、[Project]ウィンドウ > Standard Assets > Characters > ThirdPersonCharacter > Prefab > AIThirdPersonController をシーンに配置。

AIThirdPersonController を選択して [Inspector]ウィンドウ > AI Character Control (Script) コンポーネント > 歯車ボタン > Copy Component を選択してコピー。

そして Space Robot Kyle をシーンに配置。 [Inspector]ウィンドウ > Animator コンポーネント > 歯車ボタン > Pastte Component As New を選択。

必要な関連コンポーネントがまとめてペーストされます。

キャラクターのコンポーネント調整

Space Robot Kyle のコンポーネントの設定を行います。

Animator コンポーネントには ThirdPersonAnimatorController を割り当てます。

Cupsule Collider はキャラクターのサイズに合わせて次のように調整。物理マテリアルは ZeroFriction を割り当てます。

Nav Mesh Agent コンポーネントの設定は ThirdPersonCharacter と同じ設定にしました 。

Third Person Character (Script) コンポーネントは Jump Power を 0 に設定。ジャンプポーズのトリガーとなっているGround Check Distance の値を1 にしてジャンプポーズに切り替わらないようにしました。

NavMeshの作成

プレイヤーキャラクターがマウスクリックした位置まで経路探索を行うための NavMesh を作成します。

あらかじめ、[Hierarchy]ウィンドウ > Floor を選択。[Inspector]ウィンドウ > オブジェクト名の右側にある Static チェックボックスにチェックを入れます。

メニュー:Window > AI > Navigation を選択。[Bake]タブを選択して Max Slope とStep Height の値を変更。右下の[Bake]ボタンをクリック。

このように NavMesh が作成されました。

スクリプト作成

次に、マウスクリックした座標にキャラクターが移動する処理のスクリプトを作成します。

キャラクターを制御する方法はUnityの公式ドキュメントで掲載されているNavMeshAgantの使い方 マウスでクリックした位置へエージェントを移動させる – Unity マニュアル カメラからの Ray – Unity マニュアル を参考にしました。

以下のスクリプトはオブジェクトの上でマウスクリックをすることで NavMesh 内での行き先を指定することができます。クリックした位置はレーザービームをオブジェクトに当てるような raycast で決まります(このテクニックは カメラからの Ray を参考にするといいかもしれません)。GetComponent の関数を...
視錐台を理解する のセクションではカメラビューのどの点でもワールド空間の線に対応することを説明しました。その線を数学的に表現することが便利なときがあるので、Unity はこれを レイ オブジェクトという形で提供しています。レイはつねにビューの点に対応するので、Camera クラスは ScreenPointToRay と...

キャラクターオブジェクト Robot Kyle を選択して [Inspector]ウィンドウ > [Add Component]をクリック > New Script を選択。名前をMoveToClickPoint のスクリプトを作成して割り当てます。

作成したスクリプトは下記の通り。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// AI 関連のライブラリを使用するための宣言
using UnityEngine.AI;

public class MoveToClickPoint : MonoBehaviour
{
    // NavMeshAgent コンポーネントを格納する変数
    NavMeshAgent agent;

    //ゲーム開始時の処理
    void Start()
    {
        // 変数 agemt に NavMeshAgent コンポーネントを格納する
        agent = GetComponent<NavMeshAgent>();
    }

    //ゲーム実行中の処理
    void Update()
    {
        // マウス左クリックされたとき
        if (Input.GetMouseButtonDown(0))
        {
            // カメラから発射したレイが衝突したオブジェクトを格納する変数 hit を宣言
            RaycastHit hit;
            // カメラからマウスでクリックした方向にレイを発射して ray に格納
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            // もし発射したレイがコライダーと衝突したら(衝突検知最大距離 100)
            if (Physics.Raycast(ray, out hit, 100))
            {
                // 変数 hit の座標を NavMeshAgent の目標点に渡す
                agent.destination = hit.point;
            }
        }
    }
}

シーンを再生して動作確認。ちゃんとマウスクリックした場所にキャラクターが移動します。

マウスクリックした位置にエフェクトを表示する

キャラクターの目標位置がクリックしただけだと視覚的に分かりにくいので、エフェクトを表示してみます。

こちらのページ 【Unity】タップした位置にエフェクトを表示する – テラシュールブログ を参考にさせていただきました。

スマホでよくあるような、タップした位置にエフェクトを表示させる表現の作り方について、少しメモします。 タップした位置(カメラから見た3D座標)を取得 タップエフェクトを表示 エフェクトだけを表示するカメラの設定 おまけ:最前面にパーティクルを表示する タップした位置にエフェクトを表示 おまけ:何故ParticleSts...

パーティクルを発生させるオブジェクトを作成

[Hierarchy]ウィンドウ > [Create]ボタン > Create Empty を選択して空オブジェクトを作成。名前をClick Point に変更します。 [Inspector]ウィンドウ > [Add Component]をクリック > Particle Systemを選択。コンポーネントの基本パラメータはは下記のように設定しました。

さらに Size Over Lifetime のパラメータを追加してサイズを調整。

そして Renderer のパラメータは 標準のパーティクルテクスチャを使用し、 水平のビルボードに設定、パーティクルがステージオブジェクトと干渉しないように基点Y座標を調整しました。

スクリプトの修正

先に作成したスクリプト MoveToClickPoint にパーティクルを発生させるコードを追加します。マーカー部分が追加したコードです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// AI 関連のライブラリを使用するための宣言
using UnityEngine.AI;

public class MoveToClickPoint : MonoBehaviour
{
    // NavMeshAgent コンポーネントを格納する変数
    NavMeshAgent agent;
    // パーティクルコンポーネントを格納する変数
    public ParticleSystem clickEffect;

    //ゲーム開始時の処理
    void Start()
    {
        // 変数 agemt に NavMeshAgent コンポーネントを格納する
        agent = GetComponent<NavMeshAgent>();
    }

    //ゲーム実行中の処理
    void Update()
    {
        // マウス左クリックされたとき
        if (Input.GetMouseButtonDown(0))
        {
            // カメラから発射したレイが衝突したオブジェクトを格納する変数 hit を宣言
            RaycastHit hit;
            // カメラからマウスでクリックした方向にレイを発射して ray に格納
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            // もし発射したレイがコライダーと衝突したら(衝突検知最大距離 100)
            if (Physics.Raycast(ray, out hit, 100))
            {
                // 変数 hit の座標を NavMeshAgent の目標点に渡す
                agent.destination = hit.point;
                // 変数 hit の座標を パーティクルコンポーネントの座標に渡す
                clickEffect.transform.position = hit.point;
                // パーティクルを発生させる
                clickEffect.Emit(1);
            }
        }
    }
}

スクリプトを保存したら Move To Click Point (Script) コンポーネントの clickEffect フィールドに パーティクルを発生させるオブジェクト Click Point を割り当てます。

WebGLサンプル

ここまでの内容を動作確認して WebGLでビルドしてみました。マウスクリックするとクリックした場所にパーティクルが発生し、キャラクターが移動します。
画像クリックで再生(ファイルサイズ:約14MB)

corevale