2物体の衝突

ここはそれほど面白いことはないと思うよ。

[
前の記事へ]  [力学の目次へ]  [次の記事へ]


 これまで見てきた運動量保存則とエネルギー保存則を使えば、2 つの物体が衝突した後でそれぞれの速度がどうなるかを計算することが出来る。

 物体 A (質量\( m\sub{A} \))の衝突前と後の速度をそれぞれ\( v\sub{A} \)\( v'\sub{A} \)
物体 B (質量\( m\sub{B} \))の衝突前と後の速度をそれぞれ\( v\sub{B} \)\( v'\sub{B} \)とすると、

 運動量保存則より、

\[ \begin{align*} m\sub{A} v\sub{A} + m\sub{B} v\sub{B} = m\sub{A} v'\sub{A} + m\sub{B} v'\sub{B} \tag{1} \end{align*} \]
 エネルギー保存則より、
\[ \begin{align*} \frac{1}{2} m\sub{A} v\sub{A}^2 + \frac{1}{2} m\sub{B} v\sub{B}^2 \ =\ \frac{1}{2} m\sub{A} {v'\sub{A}}^2 + \frac{1}{2} m\sub{B} {v'\sub{B}}^2 \tag{2} \end{align*} \]
の 2 つの条件式が作れる。

 これを解けばいいのだが、計算が面倒くさい。難しくはないが面倒なのだ。そこで、もっと簡単に計算できる方法がある。

 エネルギー保存法則を使うのをやめて、相対速度からの条件を使えばいい。エネルギーが保存する時、衝突前の 2 物体の相対速度は衝突後の相対速度と同じになる。このような衝突を「弾性衝突」という。

\[ \begin{align*} v'\sub{A} - v'\sub{B} \ =\ - (v\sub{A} - v\sub{B}) \tag{3} \end{align*} \]
 (1) 式と (3) 式の連立方程式を解けば、簡単に衝突後の速度が求められる。


余談だが・・・

 エネルギー保存則からの条件 (2) の方を使ってコツコツと解いた場合、2 通りの解が得られる。それは、衝突をしないで通りすぎる場合(それでも運動量とエネルギーは変わらないので 2 つの条件を満たす解として正しい)の解と、衝突した結果の解である。

 相対速度の条件 (3) 式を使った場合には解は 1 つしか求まらないが、もう 1 つの解が欲しければ、次のような衝突しなかった場合の相対速度の条件を使って解けばよい。

\[ \begin{align*} v'\sub{A} - v'\sub{B} \ =\ v\sub{A} - v\sub{B} \tag{4} \end{align*} \]
 ここで (3) 式と (4) 式の 2 つの条件を合わせれば、
\[ \begin{align*} ( v'\sub{A} - v'\sub{B} )^2 \ =\ ( v\sub{A} - v\sub{B} )^2 \tag{5} \end{align*} \]
と書けるのであるが、この条件式 (5) とエネルギー保存則からの条件式 (2) とは形が全く違うのにどうして同じ解が得られる事になるのか、なるほどと一目で納得できるようなエレガントな証明が出来なくてちょっと胸につかえている。


ゲームに使う場合

 キャラクタゲームなどでは、現実的な動きをさせるより感性に頼って作った方が逆に本物らしく見えるものだが、最近は妙に映像がリアルなものが流行りで、動きも現実的なものが求められることが多くなってきた。

 これから書くことは「ゲームで衝突を計算したいけどどうも計算は苦手だよ」という人に参考にしてもらいたい。

 運動量保存の法則

mv + MV = mv' + MV'

と、衝突後の相対速度の関係式

v' - V' = - elast * ( v - V )

を連立させて解けばよい。

 ここで、elast は「跳ね返り係数」で、 elast = 1 なら弾性衝突。elast = 0 なら二つはべったりとくっついてしまうことになる。elast = 0.5 などに設定すれば、ゴムボールやスポンジボールのような跳ね返りを表現できる。

 連立式を解いた結果は下のようになる。そのまま使える形で書いておいた。たいしたものではないので自由に持っていってもらって構わない。

*******************************************

float mass1, mass2;		// 質量
float newV1, newV2;		// 衝突後の速度
float v1, v2;			// 衝突前の速度
float elast = 1.0f;		// 弾性係数

newV1 = ( ( mass1 - mass2 * elast ) * v1 + ( mass2 + mass2 * elast ) * v2  )
                                                           / ( mass1 + mass2 );
newV2 = ( ( mass2 - mass1 * elast ) * v2 + ( mass1 + mass1 * elast ) * v1  )
                                                           / ( mass1 + mass2 );


式の改良

 掲示板で「Jei」さんから、もっと効率のいい方法がありますよ、という指摘を頂いた。許可を得て、ここで紹介させてもらうことにする。

*******************************************

float mass1, mass2;		// 質量
float newV1, newV2;		// 衝突後の速度
float v1, v2;			// 衝突前の速度
float elast = 1.0f;		// 弾性係数

newV1 = ( -v1 + v2 )*( 1 + elast )/( mass1/mass2 + 1 ) + v1;
newV2 = ( -v2 + v1 )*( 1 + elast )/( mass2/mass1 + 1 ) + v2;

*******************************************

 見ただけで以前より効率が良さそうだと分かるが、実際に

A = ( 1 + elast )/( mass1/mass2 + 1 )

の部分を予め計算しておくことで、

newV1 = ( -v1 + v2 ) * A + v1;

のように毎回、1 回の掛け算、2 回の加算だけで次のターンでの速度が求められることになる。

 証明は以下の通り。分かり易くなるように記号を簡単にしてある。

new_v = { (m - M*elast) * v + (M + M*elast) * V } / (m + M)
      = { (m - M*elast) * v + (M + M*elast) * V } / (m + M)              + v - v
      = { (m - M*elast -[m + M] ) * v + (M + M*elast) * V } / (m + M)    + v
      = { ( -M*elast - M ) * v + (M + M*elast) * V } / (m + M)           + v
      = { -( M*elast + M ) * v + (M + M*elast) * V } / (m + M)           + v
      = (-v + V) * (M + M*elast) / (m + M)       + v
      = (-v + V) * (1 + elast) / (m/M + 1)       + v

 ちなみに、

newV1 - v1 = ( -v1 + v2 ) * A

であるから、衝突前後の速度差も簡単に求められ( 1 回の掛け算、1 回の加算で済む)、どれだけの力を受けたかも容易に把握できる、とのことです。お見事!