今回は、LookAt() 関数 と Distance() 関数を使ってプレイヤーキャラクターが近づくと追いかけてきて、一定の距離で停止する敵キャラクターオブジェクトの処理を試してみました。
まず、プロジェクトにアセットストアから Standard Assets をダウンロードしてインポートします。
Standard Assets の Prototyping に含まれる床のプレハブオブジェクト FloorPrototype64x01x64 を配置。プレイヤーキャラクターとして Standard Assets の Characters に含まれる ThirdPersonController を配置しました。
ThirdPersonController に標準で設定されているマテリアルはグレーですが、以前アセットストアで公開されていたSample Assets (beta) for Unity 4.6 に含まれていたカラーマテリアルに差し替えました。
敵キャラクターはプリミティブの Capsle と Cube を組み合わせて作成。
Main Camera には Standard Assets の Utility に含まれる SmoothFollow スクリプトをアタッチ。カメラターゲットはプレイヤーキャラクターの ThirdPersonController の子階層にEmptyオブジェクトを追加して設定しました。
特定のオブジェクトの方向を向かせる関数 LookAt() を使用しています。
Transform-LookAt – Unity スクリプトリファレンス
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ApproachTarget : MonoBehaviour { // ターゲットオブジェクトの Transformコンポーネントを格納する変数 public Transform target; // ゲーム実行中に毎フレーム実行する処理 void Update() { // オブジェクトを変数 target の座標方向に向かせる transform.LookAt(target); } }
スクリプトを保存して敵キャラクターにアタッチ。Target フィールドにプレイヤーキャラクターの ThirdPersonController を割り当てます。
シーンを再生すると、プレイヤーキャラクターの座標に向かってお辞儀をしてしまいます。うーん困った。
ということで、スクリプト ApproachTarget を修正してXとY座標は自分自身の座標を参照し、Y座標だけターゲットオブジェクトを参照する処理を追加します。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ApproachTarget : MonoBehaviour { // ターゲットオブジェクトの Transformコンポーネントを格納する変数 public Transform target; // ゲーム実行中に毎フレーム実行する処理 void Update() { // 変数 targetPos を作成してターゲットオブジェクトの座標を格納 Vector3 targetPos = target.position; // 自分自身のY座標を変数 target のY座標に格納 //(ターゲットオブジェクトのX、Z座標のみ参照) targetPos.y = transform.position.y; // オブジェクトを変数 targetPos の座標方向に向かせる transform.LookAt(targetPos); } }
シーンを再生して動作を確認。これでOKです。
次に敵キャラクターがプレイヤーキャラクターに近づく処理を追加します。プレイヤーキャラクターが敵キャラクターに一定距離に近づくとプレイヤーキャラクター方向に移動。一定距離近づくと停止するようにしました。
一定距離の判定を行うために2点間の距離を測る関数 Distance() を使用しています。
Vector3-Distance – Unity スクリプトリファレンス
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ApproachTarget : MonoBehaviour { // ターゲットオブジェクトの Transformコンポーネントを格納する変数 public Transform target; // オブジェクトの移動速度を格納する変数 public float moveSpeed; // オブジェクトが停止するターゲットオブジェクトとの距離を格納する変数 public float stopDistance; // オブジェクトがターゲットに向かって移動を開始する距離を格納する変数 public float moveDistance; // ゲーム実行中に毎フレーム実行する処理 void Update() { // 変数 targetPos を作成してターゲットオブジェクトの座標を格納 Vector3 targetPos = target.position; // 自分自身のY座標を変数 target のY座標に格納 //(ターゲットオブジェクトのX、Z座標のみ参照) targetPos.y = transform.position.y; // オブジェクトを変数 targetPos の座標方向に向かせる transform.LookAt(targetPos); // 変数 distance を作成してオブジェクトの位置とターゲットオブジェクトの距離を格納 float distance = Vector3.Distance(transform.position, target.position); // オブジェクトとターゲットオブジェクトの距離判定 // 変数 distance(ターゲットオブジェクトとオブジェクトの距離)が変数 moveDistance の値より小さければ // さらに変数 distance が変数 stopDistance の値よりも大きい場合 if (distance stopDistance) { // 変数 moveSpeed を乗算した速度でオブジェクトを前方向に移動する transform.position = transform.position + transform.forward * moveSpeed * Time.deltaTime; } } }
編集したスクリプト ApproachTarget を保存し、アタッチした敵キャラクターの[Inspector]ウインドウでコンポーネントのパラメータをこのように設定しました。
敵キャラクターオブジェクトをプレハブに変換して複数配置。Standard Assets の Prototyping に含まれるプレハブオブジェクト JoinOuterPrototype02x06x02 を組み合わせてステージの壁を作りました。
今回の内容をWebGLでビルドしてみました。画像クリックでファイルがダウンロード、再生されます。(ダウンロードサイズ:約23MB)
今回作成したシーンでは、敵キャラクターの制御に当たり判定を組み込んでいないので障害物のすり抜けてしまい、高低差に追従していません。
キャラクターを追従して接近する一番簡単な方法は Rigidbody と NavMesh Agent コンポーネントを使用する方法ですが、今回の方法を改造する方法でもう少し考えてみたいと思います。
View Comments
これは3Dのみで、2Dでは使えませんか?