概要
Unityは物理エンジンであり、
これを用いて物理実験をシミュレーションすることが可能である。
今回はUnityを用いて「すっとびボール」をシミュレーションする。
環境
Unity 2019.3.7f1
仕様
上の段のボール(直径1m)を高さ10mから落とす。
下の段のボール(直径1.5m)が床に着地したとき、上の段のボールが高く跳ねる。
実装
まず、床を実装する。
ヒエラルキーウィンドウで座標が(0,0,0)でScaleが(1,1,1)の
Planeを作る。
次に、スーパーボールとなる球を実装する。
ヒエラルキーウィンドウにScaleが(1,1,1)で座標が(0,10,0)のSphereをBall1とし、
Scaleが(1.5,1.5,1.5)で座標が(0,8.75,0)のSphereをBall2として作る。
すなわち、上の段のボールがBall1、下の段のボールがBall2となる。
(Ball1とBall2のマテリアルを変更しておくと見やすい。私はBall1を赤、Ball2を青とした。)
Ball1とBall2にRigidbodyをアタッチし、
Ball1の方のRigidbodyのMassを1に、Ball2の方のRigidbodyのMassを3にする。
ボール用のPhysic Materialを作る。
プロジェクトウィンドウにPhysic Materialを作り、
Bouncinessを0.9にする。
これをBall1とBall2のSphere ColliderのMaterialに入れる。
ここまでやれば、シーンウィンドウが以下の画像のようになっているはずである。
ここからスクリプトを書いていく。
スクリプトをこのように書く。
public class GalileanCannon : MonoBehaviour
{
public Rigidbody ball1;
public Rigidbody ball2;
private float v0;
private float v1;
private float v2;
private float e1 = 0.9f;
private float e0 = 0.9f;
private bool flag = true;
private bool isGrounded = false;
void Start()
{
ball1.isKinematic = true;
ball2.isKinematic = true;
//速度を求める
v0 = Mathf.Sqrt(2 * 9.81f * (ball2.transform.position.y - (ball2.transform.localScale.y / 2.0f)));
v1 = ((e0 * ball2.mass - (e0 * e1 + e1 + 1) * ball1.mass) * v0) / (ball2.mass + ball1.mass);
v2 = (((e0 * e1 + e0 + e1) * ball2.mass - ball1.mass) * v0) / (ball2.mass + ball1.mass);
}
void FixedUpdate()
{
//スペースキーを押したら開始
if (Input.GetKeyDown(KeyCode.Space))
{
ball1.isKinematic = false;
ball2.isKinematic = false;
}
//ball2が地面についたらball1が跳ねる
if(isGrounded == true && flag == true)
{
ball2.velocity = new Vector3(0, v1, 0);
ball1.velocity = new Vector3(0, v2, 0);
isGrounded = false;
flag = false;
}
}
void OnCollisionEnter(Collision collision)
{
//ball2が地面と接触したかを一回だけ判定する
if (collision.gameObject.name == "Ball2" && flag == true)
{
isGrounded = true;
}
}
}
変数を見てみよう。
public Rigidbody ball1;
public Rigidbody ball2;
private float v0;
private float v1;
private float v2;
private float e1 = 0.9f;
private float e0 = 0.9f;
private bool flag = true;
private bool isGrounded = false;
ball1は上の段のボール、ball2は下の段のボールである。
v0はball2が地面と接触する直前の速度、
v1はball2が地面と衝突したあとのball2の速度、
v2はball2が地面と衝突したあとのball1の速度である。
e1、e0は反発係数である。
isGroundedは地面に接触したかどうかを判定するものであり、
flagは地面と衝突した最初の1回だけシミュレーションを行うための判定である。
スクリプトの動作は、スクリプトに書いてあるので割愛する。
このスクリプトをPlaneに加え、
スクリプトのball1とball2にそれぞれBall1とBall2を入れる。
これで完成である。
あとは再生ボタンを押してスペースキーを押せばシミュレーションが始まる。
カメラの位置を見やすい位置に変更するのを忘れずに。
まとめ
オブジェクトを作り、計算式をスクリプトに書く。
計算式さえ理解すれば、スクリプトはさほど難しくはない。
今回はこのようなスクリプトになったが、もっと良いスクリプトがありそうなので、
自分でも考えてみてください。
参考文献
塚本浩司:「すっとびボールの研究史 物理教育 49巻6号」,2001年12月
P.537-541
Wikipedia
https://ja.wikipedia.org/wiki/%E3%81%99%E3%81%A3%E3%81%A8%E3%81%B3%E3%83%9C%E3%83%BC%E3%83%AB
(Wikipediaの途中式が異なっているので、お気をつけて)