34

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

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

前もって感謝します!

4

6 に答える 6

123

サークル間の衝突は簡単です。2つの円があると想像してください。

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

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

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

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

(x2-x1)^2 + (y2-y1)^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を意味します)。

于 2009-11-15T06:02:37.433 に答える
10

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-y1)^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 つのタイムステップでボール同士がすれ違うという問題が発生する可能性があります。この問題を解決する方法はいくつかありますが、最も簡単な方法は、動きが速すぎないようにすることです...

于 2009-11-15T06:48:44.210 に答える
8

このサイトでは、物理を説明し、アルゴリズムを導出し、 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;
}
于 2009-11-15T07:42:00.297 に答える
2

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

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

于 2009-11-17T13:57:17.150 に答える
1

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

于 2009-11-15T07:06:46.687 に答える
0

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

これが実装している場合、「X 軸または Y 軸の衝突?」という質問に対する正しい答えが得られます。しかし、ここで非常に多くの回答が得られ、利用できないように見える理由は、

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

  • 答えを正しく使用していません。

私たちの多くは跳ねるボール プログラムをプログラムしたことがあると思いますが、オクタントと軸に基づいて衝突をモデル化しようとした人は誰もいないと思います。だから私はあなたが非常に独創的な新しいアプローチを持っているか、単に間違っていると思います. したがって、戻って方法と仮定を確認することをお勧めします。

于 2009-11-15T08:18:59.833 に答える