ボールやレーザーが壁から跳ね返った後の軌跡を求めたい場合はどうすればいいの?
壁に対する反射ベクトルを使って求められるわ。反射ベクトルはUnity APIを使って簡単に得られるの。
ある平面で反射したベクトルを求めたい場合、Vector3.Reflectメソッドを用いれば簡単に取得できます。
Rigidbody rb;
・・・(中略)・・・
// 入射ベクトル(速度)
var inDirection = rb.velocity;
// 法線ベクトル
var inNormal = transform.up;
// 反射ベクトル(速度)
var result = Vector3.Reflect(inDirection, inNormal);
2次元版のVector2.Reflectメソッドも用意されています。
本記事で、実際の使用例を示しながら、これらメソッドの使い方を解説していきます。
- Unity 2021.2.0f1
Vector3.Reflectメソッド
次のような形式になっています。
public static Vector3 Reflect(Vector3 inDirection, Vector3 inNormal);
引数のinDirectionには面に向かう入射ベクトル、inNormalには平面の法線ベクトルを指定します。
戻り値は、平面から反射したベクトルとなります。
注意点として、引数inNormalは必ず長さ1に正規化されている必要があります。
Vector2.Reflectメソッド
こちらはVector2版です。2Dで扱いたい場合はこちらのほうが適しています。
public static Vector2 Reflect(Vector2 inDirection, Vector2 inNormal);
引数と戻り値の形式はVector3.Reflectメソッドとほぼ一緒です。
inDirectionには入射ベクトル、inNormalには反射する線に対する法線ベクトルを指定します。
戻り値はVector2型の反射ベクトルです。
こちらもVector3.Reflectメソッドと同様、引数inNormalは正規化されている必要があります。
使用例
前述の反射ベクトルを求めるメソッドを使った例を紹介します。
ボールを反射させるサンプル
平面にぶつかってくる球体を反射させるサンプルスクリプトです。
using UnityEngine;
public class BallReflector : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
// Triggerで接触したオブジェクトは
// 全てボールとみなすことにする
var rb = other.GetComponent<Rigidbody>();
if (rb == null) return;
// 入射ベクトル(速度)
var inDirection = rb.velocity;
// 法線ベクトル
var inNormal = transform.up;
// 反射ベクトル(速度)
var result = Vector3.Reflect(inDirection, inNormal);
// バウンド後の速度をボールに反映
rb.velocity = result;
}
}
このスクリプトは、次のように平面にアタッチして使うことを想定しています。
OnTriggerEnterイベントで衝突したオブジェクトをすべてボールとみなし、反射処理を行っています。
そのため、平面側のコライダーのIs Triggerにチェックを入れておきます。
実行結果
平面にボールがぶつかると、平面に対して反射するようになります。
物理演算による反射でないことが特徴です。
さいごに
ある面に入射したベクトルの反射ベクトルは、Vector3.ReflectやVector2.Reflectメソッドを使うと簡単に計算できます。
このメソッドは、内部的には内積を使ったベクトル計算を行っています。内部実装が気になる方は、公式のGitHubソースをご覧ください。
Rigidbodyによる物理演算を使わない反射を実現したい場合に重宝するでしょう。