2011-04-21 108 views
1

我在執行分離軸定理時遇到了困難 - 雖然碰撞檢測部分按照原樣工作,但返回的最小平移向量是錯誤的。如果我嘗試使用它來移動碰撞的多邊形,它將放置在其前一個位置的旁邊(有時與另一個多邊形相交),或者放置在屏幕上不再可見的一側。碰撞響應問題(SAT)

我試圖複製here中的代碼以嘗試修復它,但是,這也不起作用。但我不確定是什麼導致了這個問題,因爲我現在已經多次重寫了所有內容,所以不應該有任何錯別字。

我意識到這可能是明顯的,但我已經花了兩天多的時間盯着這個,我找不到它。

我爲大量的代碼表示歉意 - 我不知道我搞亂了什麼,所以我不能縮短它。

ETA:固定。此外,似乎無論是那裏的原代碼是一個錯誤或座標系統是不同的:

if (dotProduct(d, move_axis) < 0.0f) move_axis = -move_axis;

實際上應該是

if (dotProduct(d, move_axis) > 0.0f) move_axis = -move_axis;

void Polygon2d::calcEdges() 
{ 
    sf::Vector2f v1, v2; 
    edges.clear(); 

    for (unsigned int i = 0; i < vertices.size(); i++) 
    { 
     v1 = vertices[i]; 
     if ((i + 1) >= vertices.size()) v2 = vertices[0]; 
     else v2 = vertices[i + 1]; 

     edges.push_back(v2 - v1); 
    } 
} 

void Polygon2d::calcCenter() 
{ 
    float x = 0; 
    float y = 0; 

    for (unsigned int i = 0; i < vertices.size(); i++) 
    { 
     x += vertices[i].x; 
     y += vertices[i].y; 
    } 

    center.x = x/vertices.size(); 
    center.y = y/vertices.size(); 
} 

void Polygon2d::move(float x, float y) 
{ 
    for (unsigned int i = 0; i < vertices.size(); i++) 
    { 
     vertices[i].x += x; 
     vertices[i].y += y; 
    } 
    calcEdges(); 
    calcCenter(); 
} 

碰撞功能:

struct CollisionResult 
{ 
    bool collision; 
    sf::Vector2f move_axis; 
}; 

void normalise(sf::Vector2f& v) 
{ 
    float length = sqrt(v.x*v.x + v.y*v.y); 

    if (length != 0.0f) 
    { 
     v.x /= length; 
     v.y /= length; 
    } 
    else return; 
} 

float dotProduct(const sf::Vector2f a, const sf::Vector2f b) 
{ 
    float dp = a.x*b.x + a.y*b.y; 

    return dp; 
} 

void project(const sf::Vector2f axis, const Polygon2d& p, float& min, float& max) 
{ 
    float dp = dotProduct(axis, p.vertices[0]); 

    min = dp; 
    max = dp; 

    for (unsigned int i = 1; i < p.vertices.size(); i++) 
    { 
     dp = dotProduct(axis, p.vertices[i]); 

     if (dp < min) 
     { 
      min = dp; 
     } 

     else if (dp > max) 
     { 
      max = dp; 
     } 
    } 
} 

float distance(float minA, float maxA, float minB, float maxB) 
{ 
    if (minA < minB) return minB - maxA; 
    else return minA - maxB; 
} 


CollisionResult collision(const Polygon2d& p1, const Polygon2d& p2) 
{ 
    sf::Vector2f edge; 
    sf::Vector2f move_axis(0,0); 
    sf::Vector2f mtd(0,0); 

    float min_dist = FLT_MAX; 

    CollisionResult result; 

    for (unsigned int i = 0; i < p1.vertices.size() + p2.vertices.size(); i++) 
    { 
     if (i < p1.vertices.size()) // or <= 
     { 
      edge = p1.edges[i]; 
     } 
     else 
     { 
      edge = p2.edges[i - p1.vertices.size()]; 
     } 

     sf::Vector2f axis(-edge.y, edge.x); 
     normalise(axis); 

     float minA = 0; 
     float minB = 0; 
     float maxA = 0; 
     float maxB = 0; 

     project(axis, p1, minA, maxA); 
     project(axis, p2, minB, maxB); 

     if (distance(minA, maxA, minB, maxB) > 0.0f) 
     { 
      result.collision = false; 
      result.move_axis.x = 0.0f; 
      result.move_axis.y = 0.0f; 

      return result; 
     } 

     float dist = distance(minA, maxA, minB, maxB); 

     abs(dist); 

     if (dist < min_dist) 
     { 
      min_dist = dist; 
      move_axis = axis; 
     } 
    } 

    result.collision = true; 

    sf::Vector2f d = p1.center - p2.center; 
    if (dotProduct(d, move_axis) < 0.0f) move_axis = -move_axis; 
    result.move_axis = move_axis * min_dist; 

    return result; 
} 

回答

0

看來你的病情result.collision是落後的:如果由於某種軸的距離爲正,則條件應設置爲true,但在你的代碼:

if (distance(minA, maxA, minB, maxB) > 0.0f) 
    { 
     result.collision = false; 
     result.move_axis.x = 0.0f; 
     result.move_axis.y = 0.0f; 

     return result; 
    } 

此外,進一步的代碼:

​​

我想這應該是

dist = abs(dist); 

這很難,因爲以前的問題(有相反的邏輯)雖然判斷。

+0

'dist = abs(dist);'這個修正了它。有點奇怪,因爲我之前檢查過它,它似乎工作正常。感謝您的幫助。 – grue 2011-04-21 10:49:39

+0

順便說一下,條件沒有任何問題 - 如果距離是正數,多邊形投影之間存在間距,它們不能重疊。 – grue 2011-04-21 11:06:54

+0

@grue是的,我的壞。 – anatolyg 2011-04-21 11:13:15