脱初心者を目指すUnityブログ。
今日は Vector3 について基礎を軽く確認しつつ、よく使う関数を調べて整理してみたいと思います。
Vector3とは
Vector3 は、Unityで3Dの位置や方向 (ベクトル) を表すために使用する構造体です。
float 型の値を3つまとめて保持しており x, y, z の変数でアクセスすることができます。
位置情報の Transform 、速度情報の Rigidbody などを扱う際に使用します。
向きと大きさ(長さ)を持つ”矢印” と考えるとイメージしやすいです。
実用基礎
一番わかり易い Transform Position を例に、軽く実用例を挙げてみます。
・値を取得
//自分自身のPositionを取得しVector3 型変数に格納。
Vector3 vec = transform.position;
// x,y,z 変数で特定の座標を取得し上書き。(例としてメインカメラのy座標)
vec.y = Camera.main.transform.position.y;
・newを使って新しく定義
// (x,y,z) の順に引数を与えてVector3データを新規作成
Vector3 vec = new Vector3 (1.0f , 2.0f , 3.0f);
・値を変更
Vector3 vec = transform.position;
// new で初期化して新しい値を代入
vec = new Vector3 (1.0f , 2.0f , 3.0f);
// x,y,z 変数で特定の座標を変更
vec.x = 4.0f;
// Unityが用意しているStatic変数を使って値を変更。例えば zero は(0, 0, 0) と書くのと同じ。
vec = Vector3.zero;
//構造体なので、値をセットし直さないと反映されない。
transform.position = vec
その他、Vector3 型変数同士で直接計算することや 比較演算に使うこともできます。
構造体とは
先程の「値を変更」のところで触れましたが、Vector3 型変数の値を変更しただけではUnity上の位置情報は変更されません。これは 参照型 と 値型 の違いに起因しています。
・クラス(class) は参照型
参照型では、値そのものではなく「メモリのここに設計図があります」という参照情報を渡しています。そのため値を変更した際、参照先の値が直接変更されることになります。
例えば下記の例だと、Rigidbody クラスの useGravity 変数 の値を直接変更しています。
void Start() { //取得と変更 Rigidbody rb = GetComponent<Rigidbody>(); rb.useGravity = true; }
・構造体(struct) は値型
それに対して値型では、値そのものをコピーして渡しています。
そのため、コピー先の値を変更してもコピー元の値は変化しません。変更を反映させるには新しい値を改めてセットし直す必要があります。
void Start() { //取得と変更 Vector3 vec = transform.position; vec = new Vector3(1.0f, 2.0f, 3.0f); //変更した値をセットし直す transform.position = vec; }
Vector3 の便利な変数
Unity スクリプトリファレンス を見ながら、使う機会が多そうな変数について調べてまとめてみたいと思います。
Vector3.magnitude
ベクトルの長さをfloatで取得できます。Rigidbody の velocity など、力を求める際などに使われるようです。
private void Start() { //例1 ベクトルの長さを求める Vector3 vec = transform.position; Debug.Log(vec.magnitude); //x^2 + y^2 + z^2 の平方根が求められる }
public Rigidbody rb; private void Update() { //例2 力を加える+速さを求める if (Input.GetKey(KeyCode.Space)) { rb.AddForce(0, 1, 0, ForceMode.Impulse); } float speed = rb.velocity.magnitude; Debug.Log(speed); }
Vector3.sqrMagnitude
ベクトルの長さの2乗の値をfloatで取得できます。magnitude や Distance と違い平方根の計算をしない為、処理が軽くなります。単純な距離の比較をする際にはこちらを使うよう、公式に推奨されています。
(比較対象も2乗した値でないと間違った結果になるので注意)
public Transform target1; public Transform target2; private void Start() { //ターゲット2つの位置を取得 Vector3 target1Pos = target1.position; Vector3 target2Pos = target2.position; } private void Update() { //ターゲットと自分自身の間の距離を取得 float target1Dist = (transform.position - target1.position).sqrMagnitude; float target2Dist = (transform.position - target2.position).sqrMagnitude; //比較などで使う if(target1Dist < target2Dist) { Debug.Log("ターゲット1の方が近い"); } else { Debug.Log("ターゲット2の方が近い"); } }
Vector3 の便利な関数
Unity スクリプトリファレンス を見ながら、使う機会が多そうな関数について調べてまとめてみたいと思います。
Vector3.Distance(a,b);
2つのベクトルの間の距離を、float で返します。
public Transform from; public Transform to; void Example() { //fromとtoの間の距離をdistに格納 float dist = Vector3.Distance(from.position, to.position); }
Vector3.Angle(from, to);
2つのベクトル(from, to)が作る角度を、0~180°の間の float で返します。
public Transform target; void Update() { Vector3 targetDir = target.position - Camera.main.transform.position; float angle = Vector3.Angle(targetDir, Camera.main.transform.forward); if(angle < 5.0f) { Debug.Log("カメラの正面にあるよ"); } }
Vector3.SignedAngle(from, to, axis);
2つのベクトル(from, to)が作る角度を、-180~180°の間の float で返します。
Vector3.Angle(); と似ていますが、こちらは「向きの基準軸となるVector3型変数(axis)から見て角度が正か負か」も取得できます。
public Transform target; void Update() { Vector3 targetDir = target.position - Camera.main.transform.position; float angle = Vector3.SignedAngle(targetDir, Camera.main.transform.forward, Vector3.up); Debug.Log(angle); if (angle < -5.0f) { Debug.Log("カメラの右方向にあるよ"); } else if (angle > 5.0f) { Debug.Log("カメラの左方向にあるよ"); } else { Debug.Log("カメラの正面にあるよ"); } }
Vector3.Max(a, b);
2つのベクトルのうち大きい方を返します。(小さい方を取得する際はMin関数を使います。)
void Start() { Vector3 a = transform.position; Vector3 b = new Vector3(10, 10, 0); Debug.Log(Vector3.Max(a, b)); }
Vector3.MoveTowards(from, towards, float);
主にUpdate関数内で、目標位置へ等速度で移動させる処理をする際に使われます。
2つのベクトルとfloatを引数に与え「from(現在位置) から towards(目標位置) へ float(速度) で移動」のようにし、Vector3 を返させます。
下記の実用例を参考にさせて頂きました。
ターゲットに向かって直線的に進む方法
void Update() { Vector3 from = transform.position; //自分自身の現在位置 Vector3 to = new Vector3(10, 10, 0); //目標位置を設定 float speed = 1.0f; //毎秒、from から to へ向かって1mずつ進む。toに到着すると止まる。 transform.position = Vector3.MoveTowards(from, to, speed * Time.deltaTime); }
Vector3.Leap(start, end, float);
2つのベクトルの中間を計算し、Vector3 で返します。
float には0~1の数字を入れます。つまり、0.5f を入れるとちょうど真ん中の位置が返ります。
こちらも主に、Update関数内で目標位置へ移動させる処理をする際に使われます。
似た関数に Slerp がありますが、下記記事で大変わかりやすく違いを整理して下さっています。
【Unity】Vector3.Lerp/Slerpの使い方と内部挙動
void Update() { Vector3 from = transform.position; //自分自身の現在位置 Vector3 to = new Vector3(100, 10, 0); //目標位置を設定 //毎秒、from から to の間の距離の50%ぶん進む。最初は速くてだんだん遅くなる。 transform.position = Vector3.Lerp(from, to, 0.5f * Time.deltaTime); }
Vector3.Normalize(a);
ベクトルの向きを変えずに、大きさだけ1にして返します。(ベクトルの正規化)
単位ベクトルを取得することで、様々な計算の際に扱いやすくなります。
private void Start() { Vector3 a = transform.position; a.Normalize(); Debug.Log(a); }
おわりに
少しだけVector3と仲良くなれた気がします…
また新たな気づきがあれば追記したいと思います。今回はここまで!