今回は主人公キャラクターと他のゲームオブジェクトとの距離を計算出来るようにし、ゲーム作りに使えるようにします。
わざわざ一つの記事にするほど大げさな機能を作成するわけでもないんですが・・・、他のゲームオブジェクト、例えば敵との距離を計算する事が出来れば主人公キャラクターの銃の射程内にいる敵だけにダメージを与えるという時に使えます。
その他にも敵が持っている主人公キャラクターの検知範囲(コライダ)を使わず主人公との距離によって追いかける処理に変更する。といったことも出来ます(あらかじめ距離を計算する敵を指定している場合)。
今回の機能を作成すると、
上のような感じでUIで主人公キャラクターと敵との距離を表示したり、主人公が一定の距離に近づくと敵が追いかけてくる処理が出来ます。
主人公キャラクターを動かして敵との距離を表示する
それでは機能を作成していきましょう。
主人公キャラクターの作成
主人公キャラクターはスタンダードアセットのEthanを使用し、CharacterControllerの取り付けと設定、AnimatorControllerの作成とAnimatorへの設定をしておきます。
ここら辺は
上の記事を参照して通常移動出来る主人公キャラクターを作成してください。
敵との距離を測るCalculateDistanceScriptスクリプトの作成
次に主人公キャラと敵キャラとの距離を計算するDistanceFromEnemyスクリプトを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class DistanceFromEnemy : MonoBehaviour { // 自身との距離を計算するターゲットオブジェクト [SerializeField] private Transform targetObj; // 距離を表示するテキストUI [SerializeField] private Text distanceUI; // コライダを考慮したオフセット値 private float colliderOffset; private void Start() { colliderOffset = GetComponent<CharacterController>().radius + targetObj.GetComponent<CharacterController>().radius; } // Update is called once per frame void Update () { // 距離を計算 var distance = Vector3.Distance(transform.position, targetObj.position) - colliderOffset; if (distanceUI != null) { distanceUI.text = distance.ToString("0.00m"); } else { Debug.Log(distance.ToString("0.00m")); } } } |
今回はあらかじめ距離を計算するターゲットをインスペクタで設定しておきます。
targetObjには敵のゲームオブジェクトを設定します。
distanceUIには計算した距離を表示するUIのテキストを指定します。
主人公の位置と敵の位置は足元が基点となっているので、コライダが設定されている場合はコライダの分距離を縮められません。
そこで自身のコライダと相手のコライダの半径分をオフセット値として用意し、それを距離の計算に使います。
今回は両方ともCharacterControllerを使っていますが、CapsuleColliderの場合はCharacterControllerの部分をCapsuleColliderに変更します。
Box Colliderを使っていたらSizeの半分を利用すれば大丈夫かも?
UpdateメソッドでVector3.Distanceを使って自身の位置とターゲット(敵)の位置から距離を計算し、そこにコライダ分のオフセット値を引いてお互いの距離とします。
distanceUIにはテキストUIを設定しますが、設定しなかった場合はコンソールに距離を表示する事にします。
距離を表示する時に「10.34」等と小数点以下2桁を表示したいのでToStringメソッドの引数で書式指定をしています。
これで主人公と敵との距離を計算しUIに表示する事が出来ます。
コライダ分の距離を計算しましたが、完全に距離が0となることは難しいですね。
ヒエラルキーにテキストUIを配置し、DistanceFromEnemyスクリプトのインスペクタに設定します。
主人公キャラクターは上のような設定になります。
敵キャラクターの作成
次に敵キャラクターを作ります。
敵キャラクターもスタンダードアセットのEthanを使い、マテリアルだけ変更し、主人公キャラクターと違いを作っておきます。
CharacterControllerとAnimatorControllerは主人公キャラクターと同じように設定します。
敵のスクリプトの作成
次に敵用のスクリプトを作成します。
今回は主人公が一定距離に近づいたら永遠に追いかけるだけの処理を作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyScript : MonoBehaviour { public enum State { normal, chase } private CharacterController characterController; private Animator animator; private State state; [SerializeField] private float walkSpeed = 1.5f; // ターゲットの方向を向くスピード [SerializeField] private float rotateSpeed = 1.5f; private Vector3 velocity = Vector3.zero; // 自身との距離を計算するターゲットオブジェクト [SerializeField] private Transform targetObj; // コライダを考慮したオフセット値 private float colliderOffset; // Use this for initialization void Start () { characterController = GetComponent<CharacterController>(); animator = GetComponent<Animator>(); state = State.normal; colliderOffset = GetComponent<CharacterController>().radius + targetObj.GetComponent<CharacterController>().radius; } // Update is called once per frame void Update () { // 距離を計算 var distance = Vector3.Distance(transform.position, targetObj.position) - colliderOffset; if (state == State.normal) { if (distance < 3f) { GetComponent<EnemyScript>().SetState(State.chase); } } else if(state == State.chase) { if (characterController.isGrounded) { velocity = Vector3.zero; animator.SetFloat("Speed", 1f); var targetRot = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(targetObj.position - transform.position), Time.deltaTime * 2f); transform.rotation = Quaternion.Euler(transform.eulerAngles.x, targetRot.eulerAngles.y, transform.eulerAngles.z); velocity = transform.forward * walkSpeed; } velocity.y += Physics.gravity.y * Time.deltaTime; characterController.Move(velocity * Time.deltaTime); } } public void SetState(State tmpState) { state = tmpState; } } |
walkSpeedは歩く速さ、rotateSpeedは主人公を追いかける時にそちらの方向を向く速さの設定です。
敵キャラがState.normal状態の時でターゲットである主人公キャラとの距離が3mより近くなったらState.chase状態に変更します。
State.chanse状態の時は敵キャラクターの角度を徐々に主人公の方向を向くようにQuaternion.Lerpで計算しています。
Quaternion.LookRotationはその方向の回転を計算出来るので、引数にはtargetObj.position – transform.positionで主人公の方向を渡しています。
計算した角度をそのまま敵キャラの角度にしてしまうと敵と主人公の高さが変わった場合に敵キャラクターが全身でそちらの方向を向いてしまう為、横の回転だけを変えるようにしています。
これで敵キャラクターの作成が終了しました。
敵キャラクターのインスペクタは
上のようになります。
これで機能が全て出来上がりました。
ヒエラルキー全体は
上のようになりました。
終わりに
今回の機能は単純に主人公とゲームオブジェクトとの距離を計算するだけで、既にいくつもの記事で行っている事ですが、よりシンプルな使い方をしてみました。
計算した距離を逐一UIに表示したかった為に作成した記事です。(´Д`)