2011-03-24 66 views
4

我一直在努力探測遊戲中物體之間的碰撞。現在一切都是垂直的,但是希望保持其他運動的選擇開放。這是經典的2D立體空間射擊遊戲。偶發性碰撞檢測

現在我遍歷每個對象,碰撞檢測:

for(std::list<Object*>::iterator iter = mObjectList.begin(); iter != mObjectList.end();) { 
    Object *m = (*iter); 
    for(std::list<Object*>::iterator innerIter = ++iter; innerIter != mObjectList.end(); innerIter++) { 
      Object *s = (*innerIter); 

      if(m->getType() == s->getType()) { 
       break; 
      } 

      if(m->checkCollision(s)) { 
       m->onCollision(s); 
       s->onCollision(m); 
      } 
     } 
    } 

這是我如何檢查碰撞:

bool checkCollision(Object *other) { 
     float radius = mDiameter/2.f; 
     float theirRadius = other->getDiameter()/2.f; 
     Vector<float> ourMidPoint = getAbsoluteMidPoint(); 
     Vector<float> theirMidPoint = other->getAbsoluteMidPoint(); 

     // If the other object is in between our path on the y axis 
     if(std::min(getAbsoluteMidPoint().y - radius, getPreviousAbsoluteMidPoint().y - radius) <= theirMidPoint.y && 
      theirMidPoint.y <= std::max(getAbsoluteMidPoint().y + radius, getPreviousAbsoluteMidPoint().y + radius)) { 

       // Get the distance between the midpoints on the x axis 
       float xd = abs(ourMidPoint.x - theirMidPoint.x); 

       // If the distance between the two midpoints 
       // is greater than both of their radii together 
       // then they are too far away to collide 
       if(xd > radius+theirRadius) { 
        return false; 
       } else { 
        return true; 
       } 

     } 
     return false; 
} 

的問題是它會隨機正確地檢測碰撞,但其他時間根本檢測不到。這不是if語句從對象循環中分離出來的原因,因爲對象的類型不同。物體越靠近屏幕頂部,碰撞檢測正確率越高。越靠近屏幕底部,正確檢測或甚至根本檢測到的機會就越小。但是,這些情況並不總是會發生。物體的直徑很大(10和20),看看這是不是問題,但它根本沒有幫助。

編輯 -

bool checkCollision(Object *other) { 
    float radius = mDiameter/2.f; 
    float theirRadius = other->getDiameter()/2.f; 
    Vector<float> ourMidPoint = getAbsoluteMidPoint(); 
    Vector<float> theirMidPoint = other->getAbsoluteMidPoint(); 

    // Find the distance between the two points from the center of the object 
    float a = theirMidPoint.x - ourMidPoint.x; 
    float b = theirMidPoint.y - ourMidPoint.y; 

    // Find the hypotenues 
    double c = (a*a)+(b*b); 
    double radii = pow(radius+theirRadius, 2.f); 

    // If the distance between the points is less than or equal to the radius 
    // then the circles intersect 
    if(c <= radii*radii) { 
     return true; 
    } else { 
     return false; 
    } 
} 
+0

你有沒有尚未作出變更處於Beta的回答最新版本的建議(即不平方的總和半徑兩次)?如果這解決了你的問題,你應該接受Beta的答案。如果沒有,你應該指出它還沒有工作。 – 2011-03-30 12:00:25

回答

2

這種邏輯是錯誤的:

if(std::min(getAbsoluteMidPoint().y - radius, getPreviousAbsoluteMidPoint().y - radius) <= theirMidPoint.y && 
     theirMidPoint.y <= std::max(getAbsoluteMidPoint().y + radius, getPreviousAbsoluteMidPoint().y + radius)) 
{ 
    // then a collision is possible, check x 
} 

(在大括號內的邏輯是錯的太多,但應該產生誤報,不漏報。)檢查的時間間隔期間是否發生了碰撞可棘手的;我建議現在檢查一下碰撞,然後讓它首先工作。當您檢查碰撞(現在)時,您無法獨立檢查x和y,您必須查看物體中心之間的距離。

編輯:

編輯的代碼仍然是不完全正確。

// Find the hypotenues 
double c = (a*a)+(b*b); // actual hypotenuse squared 
double radii = pow(radius+theirRadius, 2.f); // critical hypotenuse squared 

if(c <= radii*radii) { // now you compare a distance^2 to a distance^4 
    return true; // collision 
} 

它應該是這樣的:

double c2 = (a*a)+(b*b); // actual hypotenuse squared 
double r2 = pow(radius+theirRadius, 2.f); // critical hypotenuse squared 

if(c2 <= r2) { 
    return true; // collision 

} 

或本:

double c2 = (a*a)+(b*b); // actual hypotenuse squared 
double c = pow(c2, 0.5); // actual hypotenuse 
double r = radius + theirRadius; // critical hypotenuse 

if(c <= r) { 
    return true; // collision 

} 
+0

感謝您的建議,我回去並改變了y軸上的檢測以使用與我在x軸上使用的方法相同的方法我得到了相同的結果,有時碰撞被正確檢測到,有時候根本沒有檢測到碰撞。這是否表明問題可能是一些還有什麼地方? – rcapote 2011-03-24 18:49:57

-1

你內環需要在mObjectList.begin開始更新的代碼()而不是國際熱核實驗堆。

內部循環需要迭代整個列表,否則您會錯過碰撞候選者,您在外部循環中進一步發展。

+0

謝謝,但問題仍然存在。 :( – rcapote 2011-03-24 02:52:37

+0

我的第一個答案是錯誤的,我認爲你是在比較兩個不同的列表而不是列表本身 你有沒有嘗試過使用相同的碰撞標準的x和y座標嗎?我認爲x座標檢查是正確的我不明白爲什麼你需要先前的y座標 – 2011-03-24 14:36:45

+0

我之前使用座標的原因是因爲我認爲碰撞是由於運動中的步驟而動作的,如果我的精靈移動了12像素和另一個對象是10像素,有可能沒有檢測到碰撞 – rcapote 2011-03-24 18:41:40

3

兩個圓形物體發生碰撞時,其中心之間的距離是足夠小。您可以使用下面的代碼來檢查:

double distanceSquared = 
    pow(ourMidPoint.x - theirMidPoint.x, 2.0) + 
    pow(ourMidPoint.x - theirMidPoint.x, 2.0); 
bool haveCollided = (distanceSquared <= pow(radius + theirRadius, 2.0)); 

爲了檢查是否有兩個時間點之間的碰撞,你可以在時間間隔開始時檢查碰撞,並在它的結束;然而,如果物體移動速度非常快,碰撞檢測可能會失敗(我猜你已經遇到了這個問題,因爲在屏幕底部有最快速度的物體墜落)。

以下可能會使碰撞檢測更可靠(雖然仍不完美)。假設物體以恆定速度移動;然後,它們的位置是時間的線性函數:

our_x(t) = our_x0 + our_vx * t; 
our_y(t) = our_y0 + our_vy * t; 
their_x(t) = their_x0 + their_vx * t; 
their_y(t) = their_y0 + their_vy * t; 

現在可以定義它們之間的(平方)的距離作爲時間的二次函數。找出它在哪個時間取其最小值(即其導數爲0);如果此時間屬於當前時間間隔,則計算最小值並檢查其是否發生碰撞。

這必須足以幾乎完美地檢測碰撞;如果你的應用程序的工作很大程度上與自由墜落物,則可能需要細化的運動功能進行二次:

our_x(t) = our_x0 + our_v0x * t; 
our_y(t) = our_y0 + our_v0y * t + g/2 * t^2; 
+0

'pow(x,2.0)'不可能比'x * x'更快,並且可能(根據實現和硬件)要慢得多。如果在這裏'x'參數是一個複合表達式,你可以使用'inline double Square(double x){return x * x; }'。 – TonyK 2011-03-24 19:23:30

+1

@TonyK我的編譯器(gcc 4.1.2)實際上爲我做了這個優化 – anatolyg 2011-03-24 19:30:12

+0

我以前用這種方法來測試碰撞,但仍然有和有相同的結果。我使用這種方法使用代碼更新了我的原始帖子。對象的運動與您所描述的完全相同,但不受重力的影響。對象以恆定的速度移動,直到它們離開屏幕。在我的學習中,我只是勉強表達微積分,所以這只是我的數學知識。座標的導數是速度。我該怎麼做? – rcapote 2011-03-24 20:20:49