弓から矢を射出した時の計算方法
例として、弓から矢を発射したときに、矢をどのようにして移動させるかを見てみましょう。
このスクリプトはタワーディフェンスゲーム制作時に、実際に使用しているスクリプトです。なので、これだけでは動かないのですが、重要な部分がいくつかありますので、それぞれメモを記します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Arrow : MonoBehaviour
{
public Enemy targetEnemy; // 弓が捉えたターゲット
private float speed = 10; // 矢の速度
void Update()
{
if (targetEnemy == null)
{
// ターゲットがいない場合は矢を消去
Destroy(gameObject);
return;
}
// ターゲットへのベクトルを計算
var v = targetEnemy.transform.position - transform.position;
// 矢を移動させる
transform.position += v.normalized * speed * Time.deltaTime;
// 特定の距離に近付いたらHPを減らす
if (v.magnitude < 0.7f)
{
targetEnemy.hp -= 1;
if (targetEnemy.hp <= 0)
{
Destroy(targetEnemy.gameObject);
}
Destroy(gameObject);
}
}
}
どの方向に移動するのか
var v = targetEnemy.transform.position - transform.position;
まず、移動する方向を決める必要があります。そのためにはベクトルを求める必要があります。
ベクトルは簡単に言うと、向きと大きさを持つ数値です。
ベクトルの計算方法は「目標とする場所 - 現在の場所」で求める事ができます。
今回はターゲットが存在するため、ベクトルを求めて方向を決めていますが、単純に右に移動させる場合は Vector3.right
と記述します。
どれだけ移動するか
transform.position += v.normalized * speed * Time.deltaTime;
ベクトルを求めたら、実際にオブジェクトの座標を移動します。v.normalized
はベクトルから方向だけを取り出す書き方と考えてください。正確には、ベクトルの正規化と呼ばれていて、ベクトルの長さを 1.0 にした物が生成されます。正規化を行わないと、距離が近いとベクトルが小さくなり、遠いとベクトルが大きくなってしまい、距離によって速度が変化してしまいます。
Time.deltaTime
とありますが、とても重要なプロパティで、直前のフレームと今のフレーム間で経過した時間[秒]を返すプロパティです。こうすることで、距離を求める際に必要な時間を求める事ができます。後は小学校の算数と同じで、時間×速さ×方向で移動距離を算出して、現在の座標に足し算するだけです。
ターゲットに当たった判定
if (v.magnitude < 0.7f)
今回は矢を敵に発射するスクリプト処理なので、敵に当たった時にどうするのかも書かれています。ターゲットに当たった判定ですが、距離が 0.7 以下の場合には当たったと判定しています。つまり、実際には当たっていません。
実際に当たったと判定したい場合は、コライダーを設定する必要がありますし、衝突したコライダーが本当にターゲットなのかを判定する必要もあります。今回の場合はそこまで複雑な処理を必要としないため、このように距離で判定を行っています。
v.magnitude
はベクトルの長さを数値で返してくれるプロパティです。つまり、直線距離でどれだけ離れているかがこれで分かります。