壁との弾性衝突とは
入射角と反射角が同じように跳ね返り、跳ね返りの前後で速さが変わらない運動を指します。
標準の物理特性マテリアルでは挙動関係でバグが起こりやすいため、手製のものを実装しましょう。
2Dゲームの場合の実装
弾性衝突させたいオブジェクトに、Rigidbody2Dとともに下記のBouce.csをアタッチしてください。
public変数のvelocityで速度を操作しています。
AddForceなどで運動に介入しようとしても速度はvelocityで固定されます。
もし衝突以外で運動を操作する場合は、velocity変数を書き換えるか、Update関数の処理を一時的にオフにする処理を書き加えてください。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bounce : MonoBehaviour
{
public Vector2 velocity;
private void Update()
{
GetComponent<Rigidbody2D>().velocity = velocity;
}
public void OnCollisionEnter2D(Collision2D collision)
{
Vector2 velocityNext
= Vector2.Reflect(velocity, collision.contacts[0].normal);
velocity = velocityNext;
}
}
3Dゲームの場合の実装
弾性衝突させたいオブジェクトに、Rigidbodyとともに下記のBouce.csをアタッチしてください。
public変数のvelocityで速度を操作しています。
AddForceなどで運動に介入しようとしても速度はvelocityで固定されます。
もし衝突以外で運動を操作する場合は、velocity変数を書き換えるか、Update関数の処理を一時的にオフにする処理を書き加えてください。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bounce : MonoBehaviour
{
public Vector3 velocity;
private void Update()
{
GetComponent<Rigidbody>().velocity = velocity;
}
public void OnCollisionEnter(Collision collision)
{
Vector3 velocityNext
= Vector3.Reflect(velocity, collision.contacts[0].normal);
velocity = velocityNext;
}
}
仕組み
仕組みは単純です。
Vector2ないしVector3クラスにReflect関数があります
Vector3.Reflect(速度ベクトル, 法線ベクトル)
法線ベクトルとは、ざっくり言うと下図のイメージです。
ちゃんとした説明でいうと、「衝突面に垂直なベクトル」です。
速度ベクトルはvelocityで与えられます。
衝突面の法線ベクトルは、OnCollisionEnterの引数に与えられるCollisionの中のContactに含まれています。
具体的には、collision.contacts[0].normal
です。
これをReflect()
に与えることで、弾性衝突後の速度ベクトルを与えてくれます。
なぜvelocity変数を作るのか
当然の疑問として、なぜわざわざvelocity変数で速度を管理して速度の管理を不自由にするのか、なぜReflect()
にGetComponent()<Rigidbody>().velocity
を直接与えないのか、と思われると思います。
その理由としては、OnCollisionEnter()
が呼ばれる時には既にRigidbody.velocity
が既に衝突後の数値になってしまうからなんですよね。
デフォルトだと非弾性衝突(跳ね返らず、壁にひっつくような衝突)をしますが、その値が既にRigidbody.velocity
に代入されてしまい、衝突前の数値をReflect()
に与えることができなくなってしまいます。
そういった事情で、衝突前の速度ベクトルを把握するために、velocityで管理しています。
もしUpdate関数でRigidbody.velocity
を上書きしなくとも衝突前のRigidbody.velocity
を掴める実装を思いつけたら、そっちのほうがいいでしょうね、、