今回は 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 を作成します。
あらかじめ、[Hierarchy]ウィンドウ > Floor を選択。[Inspector]ウィンドウ > オブジェクト名の右側にある Static チェックボックスにチェックを入れます。
メニュー:Window > AI > Navigation を選択。[Bake]タブを選択して Max Slope とStep Height の値を変更。右下の[Bake]ボタンをクリック。
このように NavMesh が作成されました。
次に、マウスクリックした座標にキャラクターが移動する処理のスクリプトを作成します。
キャラクターを制御する方法はUnityの公式ドキュメントで掲載されているNavMeshAgantの使い方 マウスでクリックした位置へエージェントを移動させる – Unity マニュアル と カメラからの Ray – Unity マニュアル を参考にしました。
キャラクターオブジェクト 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】タップした位置にエフェクトを表示する – テラシュールブログ を参考にさせていただきました。
さらに 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でビルドしてみました。マウスクリックするとクリックした場所にパーティクルが発生し、キャラクターが移動します。
画像クリックで再生(ファイルサイズ:約14MB)