動機
Unityでビリヤードを作ろうとして、いつものようにPhysice MaterialのBounceを使おうとしたら、発射時の力が弱すぎてうまく跳ね返ってくれない事態が発生。
じゃあ自分で実装してみよう!ということに。
反射ベクトルの求め方について
詳しいベクトルの解説はこちらや、
http://nn-hokuson.hatenablog.com/entry/2018/03/30/201715
こちらをご覧ください。
https://qiita.com/edo_m18/items/b145f2f5d2d05f0f29c9
使う関数
リンク先ではずらずらと計算式が出てきたと思いますが、Unityでは一行で反射ベクトルを求められる便利関数が存在します。
Vector3 Reflect(Vector3 inDirection, Vector3 inNormal);
この関数はinDirectionに物体のvelocity、inNormalに当たった物体の法線を与えてやれば、反射ベクトルを返してくれます。
実装
次に跳ね返させるオブジェクトを用意します。今回はSphereです。
RigidBodyをつけて、y軸だけ固定します。
そして最初にボールを動かすために、velocityを変化させるスクリプトを書きます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AddPower : MonoBehaviour {
private Rigidbody rb;
private BounceCalc bounceCalc;
public float power = 1; // 発射時の力
// Use this for initialization
void Start () {
rb = this.GetComponent<Rigidbody>();
bounceCalc = this.GetComponent<BounceCalc>();
}
// Update is called once per frame
void Update () {
if(Input.GetKeyDown(KeyCode.Space)){
rb.velocity = new Vector3(power, 0, power);
// 発射時のvelocityを取得
bounceCalc.afterReflectVero = rb.velocity;
}
}
}
次に、実際に反射ベクトルを計算しているスクリプトがこちらです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BounceCalc : MonoBehaviour {
//ボールが当たった物体の法線ベクトル
private Vector3 objNomalVector = Vector3.zero;
// ボールのrigidbody
private Rigidbody rb;
// 跳ね返った後のverocity
[HideInInspector] public Vector3 afterReflectVero = Vector3.zero;
public void OnCollisionEnter (Collision collision) {
// 当たった物体の法線ベクトルを取得
objNomalVector = collision.contacts[0].normal;
Vector3 reflectVec = Vector3.Reflect (afterReflectVero, objNomalVector);
rb.velocity = reflectVec;
// 計算した反射ベクトルを保存
afterReflectVero = rb.velocity;
Debug.Log ("nomal:" + afterReflectVero);
}
// Use this for initialization
void Start () {
rb = this.GetComponent<Rigidbody> ();
}
}
この二つのスクリプトをSphereにアタッチするとBounceを使わなくてもボールが跳ね返ってくれます。