2011-09-07 112 views
0

您好我試圖實現一個簡單的球碰撞檢測算法如下解釋:http://wp.freya.no/3d-math-and-physics/simple-sphere-sphere-collision-detection-and-collision-response/碰撞響應方法

所以我實現的方法來檢查,如果發生碰撞:

private boolean advancedSphereSphere(Sphere a, Sphere b) { 

Vector2D s = a.getPos().sub(b.getPos()); 
Vector2D v = a.getVelocity().sub(b.getVelocity()); 

float r = a.getRadius() + b.getRadius(); 

double c1 = s.dot(s) - r*r; 

if(c1 < 0.0) { 
    timeToCollision = .0f; 
    return true; 
} 

double a1 = v.dot(v); 
if(a1 < 0.00001f) { 
    return false; 
} 

double b1 = v.dot(s); 
if(b1 >= 0.0) { 
    return false; 
} 

double d1 = b1*b1 - a1*c1; 
if(d1 < 0.0) { 
    return false; 
} 

timeToCollision = (float) (-b1 - Math.sqrt(d1)/a1); 

return true; 
} 

然後,我有一個的onDraw方法該循環繪製所有必要的元素,如下:

protected void onDraw(Canvas canvas) { 
    flowPhysics(false); 
    for(Sphere s : mSpheres) { 
     s.draw(canvas); 
    } 

    invalidate(); 
} 

和flowPhysics(boolean)方法出現該問題,在這一行:

for(int i=0; i < mSpheres.size(); ++i) { 
      for(int j=i+1; j < mSpheres.size(); ++j) { 

       Sphere a = mSpheres.get(i); 
       Sphere b = mSpheres.get(j); 

       if(advancedSphereSphere(a, b) || step) { 
        if(timeToCollision < dt && !step) { 
         flowPhysics(true); 
        } 

        if(step) { 
         sphereCollisionResponse(a, b); 
        } 
       } 

      } 
     } 

當advancedSphereSphere()時,第一球消失了,我查了一下,發現這個問題是在第一行的方法稱爲:如果我把別的東西在這裏

Vector2D s = a.getPos().sub(b.getPos()); 

和不要從矢量中減去b,它會畫出球(但不會發生碰撞)。上面的Java代碼大多是從這裏移植的代碼:http://wp.freya.no/websvn/filedetails.php?repname=Public&path=%2Fopengl%2Fcollisiondetect%2Fcollisiondetect.cpp

你能告訴我什麼是問題嗎?

感謝

UPDATE

private void sphereCollisionResponse(Sphere a, Sphere b) 
    { 
     double m1, m2, x1, x2; 
     Vector2D v1, v2, v1x, v2x, v1y, v2y; 
     Vector2D x = new Vector2D(a.getPos().sub(b.getPos())); 

     x.normalize(); 
     v1 = new Vector2D(a.getVelocity()); 
     x1 = x.dot(v1); 
     v1x = new Vector2D(x.multiply(x1)); 
     v1y = new Vector2D(v1.sub(v1x)); 
     m1 = a.getMass(); 

     x = new Vector2D(x.multiply(-1)); 
     v2 = new Vector2D(b.getVelocity()); 
     x2 = x.dot(v2); 
     v2x = new Vector2D(x.multiply(x2)); 
     v2y = new Vector2D(v2.sub(v2x)); 
     m2 = b.getMass(); 

     Vector2D nn = new Vector2D(v1x.multiply(m1-m2)); 
     Vector2D mm = new Vector2D(nn.divide(m1+m2)); 
     Vector2D tt = new Vector2D(v2x.multiply(2*m2)); 
     Vector2D rr = new Vector2D(tt.divide(m1+m2)); 
     Vector2D gg = new Vector2D(mm.add(rr)); 
     Vector2D ss = new Vector2D(gg.add(v1y)); 

     Vector2D nva = ss; 
     a.setVelocity(nva); 

     Vector2D nvb = new Vector2D(v1x.multiply(2*m1).divide(m1+m2).add(v2x.multiply(m2-m2).divide(m1+m2).add(v2y))); 
     b.setVelocity(nvb);  
} 
+1

「第一個球體消失」 - 是因爲你的系統認爲它與自身相撞? 「doPhysics」和「sphereCollisionResponse」做了什麼? –

+0

「step」定義在哪裏?它是如何定義的? – Dave

+0

step是flowPhysics(布爾步驟)中的參數,就像遞歸工作的幫助器一樣。 (在onDraw中,你可以看到,我有flowPhysics(false),然後我在flowPhysics()本身有遞歸如果發生碰撞,我將它設置爲true(flowPhysics(true))。 – Tzanter

回答

0

如果問題真的是在這一行

Vector2D s = a.getPos().sub(b.getPos()); 

那麼我懷疑問題可能在於你的Vector2D類。您應檢查sub方法是否只返回新的Vector2D,並且不會修改原始矢量的座標a。儘可能保持你的對象不變,這使得它們更安全。

如果不成功,答案是unit testing。學習使用JUnitTestNG將長期得到回報,但即使是一些特別的印刷聲明也可能對您有所幫助。您應該能夠檢查數學是否正確,與球體在屏幕上的顯示方式無關,並且一直這樣做可能會引導您進行更清晰的設計。

僅僅通過測試碰撞後每個球體的位置是否保持不變,並且在幾個簡單情況下速度如預期一樣,您很可能會發現代碼中的錯誤。例如,如果兩個速度都預先爲零,那麼它們之後應該爲零。如果碰撞是彈性的,並且一個球體(A)與另一個靜止球體(B)正面碰撞,則球體A應該是靜止的,球體B應該具有以A開始的速度。

我還沒有在http://pastie.org/2499691上檢查過你的代碼中的數學,但是當我設置幾個簡單的類來填充依賴關係並給它一些合理的開始條件時,它不會保留動量,所以我可以相信一些球的最終值可能會以光速飛出屏幕。

一旦你擁有了物理權利,你就可以解決任何剩餘的問題,因爲知道問題確實存在於那裏,因此安全領域的顯示是安全的。

+0

嗨。 ()方法 - 是的,但是再一次,碰撞效果很好,然後響應不起作用。你能檢查這個代碼的響應:http://pastie.org/2499691 - 我使用這個Vector2D類:http:/ /goo.gl/I4R4Y。當球碰撞時 - 第一個(a) - 消失:( – Tzanter

+0

我稍後會檢查你的代碼,但是在快速查看Vector2D之後,我認爲你想要減去()而不是sub()來避免修改原始矢量,然後你的球就可以跳到屏幕外的位置,這可能會使它看起來消失。 – Ben

+0

是的 - 我改變了減去 - 它仍然跳下我的sc子: – Tzanter