Unityでゲームを制作している際にRaycastを使って当たり判定を取得する際にRaycastが望んだ方向と距離で正しく飛ばせているかを確認する事ってありますよね?
UEだとエンジン側がRaycastの関数に光線を表示するかどうかを指定できるので楽なのですがUnityだとDrawRay等を使って自分で用意する必要があります。
今回はその時にハマってしまった事を少し書いておこうと思います。(筆者がその辺りの計算が苦手なせいですがきっと同じような人がいると信じてます。)
float distance = Vector3.Distance(target.position, player.position);
Vector3 direction = target.position - player.position;
Physics.Raycast(pos, direction, distance)
{
Debug.Log("ヒットした");
}
こんな感じで対象までの向きと距離を計算してレイを飛ばしたとします。
これだけだとレイがちゃんと飛んでいるのかわからないのでDrawRayを使って視覚化する事にしました。
float distance = Vector3.Distance(target.position, player.position);
Vector3 direction = target.position - player.position;
Debug.DrawRay(pos, direction * distance, Color.red, 5, false); // -> 追加
Physics.Raycast(pos, direction, distance)
{
Debug.Log("ヒットした");
}
これで確認するとDrawRayの光線がtargetを突き抜けてしまいます。
理由は
Vector3 direction = target.position - player.position;
この計算だと
ターゲットオブジェクトの方向を指すとともに、このベクトルの大きさは二つの位置の間の距離に等しくなるので正規化したベクトルに変えて上げないといけないようです。
Raycastの処理を見に行くと
public bool Raycast(Vector3 origin, Vector3 direction, [DefaultValue("Mathf.Infinity")] float maxDistance = float.PositiveInfinity, [DefaultValue("Physics.DefaultRaycastLayers")] int layerMask = -5, [DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal)
{
float magnitude = direction.magnitude;
if (magnitude > float.Epsilon)
{
Vector3 direction2 = direction / magnitude;
return Internal_RaycastTest(ray: new Ray(origin, direction2), physicsScene: this, maxDistance: maxDistance, layerMask: layerMask, queryTriggerInteraction: queryTriggerInteraction);
}
return false;
}
正規化しているのがわかります。
なので
float distance = Vector3.Distance(target.position, player.position);
Vector3 direction = target.position - player.position;
Vector3 normalization_dir = direction / direction.magnitude;
Debug.DrawRay(pos, normalization_dir * distance, Color.red, 5, false); // -> 正規化したベクトルで計算
Physics.Raycast(pos, direction, distance)
{
Debug.Log("ヒットした");
}
としてあげるとDrawRayの表示がRaycastと同じになります。