web-dev-qa-db-ja.com

円と円の衝突

2つのボール(円)が衝突する2Dボールゲームを開発します。今、私は衝突点を決定することで問題を抱えています(実際、それらがx軸/ y軸で衝突しているかどうかを決定しています)。 2つのボールのy座標の差がx座標の差よりも大きい場合、それらはy軸で衝突し、そうでない場合は、x軸で衝突すると考えています。私の考えは正しいですか?私はこれをゲームに実装しました。通常はうまく機能しますが、失敗することもあります。私の考えが正しいかどうか誰かに教えてもらえますか?そうでない場合、その理由は何ですか?それより良い方法はありますか?

X軸の衝突とは、円の1番目、4番目、5番目、または8番目の八分円を意味し、y軸は、円の2番目、3番目、6番目、または7番目の八分円を意味します。

前もって感謝します!

26
russell

円同士の衝突は簡単です。 2つの円があるとします。

  • 中心(x1、y1)と半径r1のC1。
  • 中心(x2、y2)と半径r2のC2。

これら2つの中心点の間に線が引かれていると想像してください。中心点からいずれかの円のエッジまでの距離は、定義により、それぞれの半径に等しくなります。そう:

  • 円の端が接している場合、中心間の距離はr1 + r2です。
  • それ以上の距離では、円は接触または衝突しません。そして
  • それ以下であれば衝突します。

したがって、次の場合に衝突を検出できます。

(x2-x1)^2 + (y1-y2)^2 <= (r1+r2)^2

中心点間の距離が半径の合計よりも小さいことを意味します。

同じ原理を3次元の球間の衝突の検出に適用できます。

編集:衝突点を計算する場合、いくつかの基本的な三角法で計算できます。あなたは三角形を持っています:

        (x1,y1)
        |\
        | \
        |  \ sqrt((x2-x1)^2 + (y2-y1)^2) = r1+r2
|y2-y1| |   \
        |    \
        |   X \
(x1,y2) +------+ (x2,y2)
         |x2-x1|

|x2-x1|および|y2-y1|は絶対値です。したがって、角度Xの場合:

        |y2 - y1|
sin X =  -------
         r1 + r2

        |x2 - x1|
cos X =  -------
         r1 + r2

        |y2 - y1|
tan X =  -------
        |x2 - x1|

角度を取得したら、それらを新しい三角形に適用して交点を計算できます。

  +
  |\
  | \
b |  \ r2
  |   \
  |  X \
  +-----+
     a

どこ:

        a
cos X = --
        r2

そう

a = r2 cos X

前の式から:

       |x2 - x1|
a = r2 -------
        r1 + r2

Aとbを取得したら、必要に応じて(a、b)による(x2、y2)オフセットの観点から衝突点を計算できます。このために、サイン、コサイン、逆サイン、コサインを計算する必要さえありません。またはそのことについての平方根。だから高速です。

しかし、正確な角度や衝突点が必要なく、オクタントが必要な場合は、タンジェントについて理解することでさらに最適化できます。

  • 0 <= tan X <= 1 for 0 <= X <= 45度;
  • tan X> = 1 for 45 <= X <= 90
  • 0> = tan X> = -1 for 0> = X => -45;
  • tan X <= -1 for -45> = X => -90;そして
  • tan X = tan(X + 180)= tan(X-180)。

これらの4度の範囲は、サースの4つのオクタントに対応します。他の4つは180度オフセットされています。上記のように、接線は次のように簡単に計算できます。

        |y2 - y1|
tan X =  -------
        |x2 - x1|

絶対値を失うと、この比率により、衝突が4つのオクタントのどれにあるかがわかります(上記の接線範囲による)。正確な八分円を計算するには、x1とx2を比較して、どちらが左端かを判断します。

他のシングルの衝突のオクタントはオフセットされます(C1のオクタント1はC2、2と6、3と7、4と8などのオクタント5を意味します)。

107
cletus

Cletusが言うように、2つのボールの半径の合計を使用します。次のように、ボールの中心間の合計距離を計算します。

Ball 1:  center: p1=(x1,y1)  radius: r1
Ball 2:  center: p2=(x2,y2)  radius: r2

collision distance: R= r1 + r2
actual distance:    r12= sqrt( (x2-x1)^2 + (y2-y2)^2 )

衝突は常に発生します(r12 <R)。 Arteliusが言うように、それらは実際にはx/y軸で衝突するべきではなく、特定の角度で衝突します。ただし、実際にはその角度は必要ありません。衝突ベクトルが必要です。これは、2つの円が衝突したときの中心の違いです。

collision vector: d12= (x2-x1,y2-y1) = (dx,dy)
actual distance:  r12= sqrt( dx*dx + dy*dy )

実際の距離を計算するときは、すでに上記のdxとdyを計算しているので、このような目的でそれらを追跡することもできます。この衝突ベクトルを使用して、ボールの新しい速度を決定できます-いくつかの要因で衝突ベクトルをスケーリングし、それを古い速度に追加することになりますが、実際の衝突に戻りますポイント:

collision point:  pcollision= ( (x1*r2+x2*r1)/(r1+r2), (y1*r2+y2*r1)/(r1+r2) )

ボールの新しい速度を見つける方法を理解するには(そして一般的には、全体の状況からより理解を深めるために)、おそらく高校の物理学の本または同等のものを見つける必要があります。残念ながら、私は良いWebチュートリアルを知りません。

ああ、それでもx/y軸にこだわりたい場合は、次のようにして正しいと思います。

if( abs(dx) > abs(dy) ) then { x-axis } else { y-axis }

失敗する理由については、詳細な情報がないとわかりにくいですが、ボールの動きが速すぎて、1つのタイムステップでボールが互いにすれ違うときに問題が発生する可能性があります。この問題を修正する方法はありますが、最も簡単な方法は、動きが速すぎないことを確認することです...

10
comingstorm

このサイトは 物理を説明アルゴリズムを導出 、および2Dボールの 衝突のコード を提供します。

この関数が以下を計算した後で、オクタントを計算します。体の重心aを基準にした衝突点の位置

/**
This function calulates the velocities after a 2D collision vaf, vbf, waf and wbf from information about the colliding bodies
@param double e coefficient of restitution which depends on the nature of the two colliding materials
@param double ma total mass of body a
@param double mb total mass of body b
@param double Ia inertia for body a.
@param double Ib inertia for body b.
@param vector ra position of collision point relative to centre of mass of body a in absolute coordinates (if this is
                 known in local body coordinates it must be converted before this is called).
@param vector rb position of collision point relative to centre of mass of body b in absolute coordinates (if this is
                 known in local body coordinates it must be converted before this is called).
@param vector n normal to collision point, the line along which the impulse acts.
@param vector vai initial velocity of centre of mass on object a
@param vector vbi initial velocity of centre of mass on object b
@param vector wai initial angular velocity of object a
@param vector wbi initial angular velocity of object b
@param vector vaf final velocity of centre of mass on object a
@param vector vbf final velocity of centre of mass on object a
@param vector waf final angular velocity of object a
@param vector wbf final angular velocity of object b
*/
CollisionResponce(double e,double ma,double mb,matrix Ia,matrix Ib,vector ra,vector rb,vector n,
    vector vai, vector vbi, vector wai, vector wbi, vector vaf, vector vbf, vector waf, vector wbf) {
  double k=1/(ma*ma)+ 2/(ma*mb) +1/(mb*mb) - ra.x*ra.x/(ma*Ia) - rb.x*rb.x/(ma*Ib)  - ra.y*ra.y/(ma*Ia)
    - ra.y*ra.y/(mb*Ia) - ra.x*ra.x/(mb*Ia) - rb.x*rb.x/(mb*Ib) - rb.y*rb.y/(ma*Ib)
    - rb.y*rb.y/(mb*Ib) + ra.y*ra.y*rb.x*rb.x/(Ia*Ib) + ra.x*ra.x*rb.y*rb.y/(Ia*Ib) - 2*ra.x*ra.y*rb.x*rb.y/(Ia*Ib);
  double Jx = (e+1)/k * (Vai.x - Vbi.x)( 1/ma - ra.x*ra.x/Ia + 1/mb - rb.x*rb.x/Ib)
     - (e+1)/k * (Vai.y - Vbi.y) (ra.x*ra.y / Ia + rb.x*rb.y / Ib);
  double Jy = - (e+1)/k * (Vai.x - Vbi.x) (ra.x*ra.y / Ia + rb.x*rb.y / Ib)
     + (e+1)/k  * (Vai.y - Vbi.y) ( 1/ma - ra.y*ra.y/Ia + 1/mb - rb.y*rb.y/Ib);
  Vaf.x = Vai.x - Jx/Ma;
  Vaf.y = Vai.y - Jy/Ma;
  Vbf.x = Vbi.x - Jx/Mb;
  Vbf.y = Vbi.y - Jy/Mb;
  waf.x = wai.x - (Jx*ra.y - Jy*ra.x) /Ia;
  waf.y = wai.y - (Jx*ra.y - Jy*ra.x) /Ia;
  wbf.x = wbi.x - (Jx*rb.y - Jy*rb.x) /Ib;
  wbf.y = wbi.y - (Jx*rb.y - Jy*rb.x) /Ib;
}
8
Leftium

私は提供された答えに同意します、それらはとても良いです。
私はあなたに小さな落とし穴を指摘したいだけです:ボールの速度が速い場合、円は与えられたステップで交差することはないので、衝突を見逃す可能性があります。
解決策は、運動の方程式を解き、衝突の正しい瞬間を見つけることです。

とにかく、ソリューションを実装する場合(X軸とY軸の比較)、古き良きピンポンが表示されます。 http://en.wikipedia.org/wiki/Pong
:)

1
avp

それらが衝突する点は、2つの円の中間点間の線上にあり、どちらかの中間点からの距離は、それぞれの円の半径です。

1
Carl Smotricz

あなたの質問にもっと直接答えるために:はい、あなたがレイアウトした規則と要件に従って、ボールが接触したときにYの差がXの差より大きい場合、それらのボールはY軸で衝突します。

これが実装しているものであれば、「X軸またはY軸の衝突?」という質問に対する正しい答えが得られます。しかし、あなたがここであなたがあまりにも多くの答えを得ているので、あなたが活用できないように思える理由は、

  • あなたは間違った質問をしています(ここではありません-あなたのプログラムで)。または

  • あなたは答えを正しく使っていません。

私たちの多くは、跳ねるボールのプログラムをプログラミングしていると思います。私たちは、オクタントと軸に基づいて衝突をモデル化しようとした人はいないと思います。だからあなたは非常に独創的な新しいアプローチをしているのか、単にそれを間違っているのだろうと思います。したがって、戻ってメソッドと前提条件を確認することをお勧めします。

0
Carl Smotricz