2011-04-21 104 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