2

我只是想“检查”两个不同几何形状的物体是否发生碰撞。一个是圆形,第二个是正方形。我搜索了谷歌以找到一个简单的示例并从中学习,因为我不知道该怎么做。我找到了这个例子,试过了,但什么也没发生。代码中大多数存在错误。请帮助我用 C 或 C++ 语言更正它。

bool Collision(int circleX, int circleY, int radius, int squareX, int squareY, int width, int height)
{
    int distance = 0;

    if(circleX < squareX) 
        distance += pow(circleX - boxX,2); //x-axis
    else if (circleX > squareX + width)
        distance += pow(circleX - squareX - width, 2);

    if(circleY < squareY) 
        distance += pow(circleY - squareY,2); //y-axis
    else if (circleY > squareY + height) 
        distance += pow(circleY - squareY - height, 2);

    if( distance <= pow(radius, 2))
        return true; 
    else    
        return false;
}
4

2 回答 2

3

首先,让我们弄清楚如何表示圆形和正方形。

在约定中,square表示如下:

  squarexX, squareY + height  ------------ squareX+ width, squareY +height
  |                                               |
  |                                               |
   squareX, squareY          ------------- squareX + width, squareY

Whilecircle由圆的坐标(circleX, circleY)radius值表示。考虑到这一点,您甚至应该能够编写自己的函数。请注意,圆没有宽度或高度。

所以在他们的代码中:

 if(circleX < squareX) distance += pow(circleX - boxX,2); //x-axis

应该

 if(circleX < squareX) distance += pow(circleX - squareX,2); //x-axis

判断正方形是否与圆形重叠/碰撞的思路如下:

  1. 假设正方形位于二维平面的原点,如果不是,我们可以将原点移动到正方形的中心
  2. 接下来,找出圆与正方形最近的边缘交点之间的距离,如果这个距离大于半径,则不重叠,否则重叠。一个特殊的情况是,如果圆位于正方形内部,那么所谓的交点就是圆本身的中心。在这种情况下,testForCollision 将返回 true。

完整的函数应该如下所示:

//this function computes the distance between center of circle
//to closest point on one of the edges of square, that edge is on the
//same side as the circle
#include <algorithm>
bool testForCollision(int circleX, int circleY, int width, int height, int radius)
{   

    int dx = std::min(circleX, (int)(width  * 0.5));
    int dx1 = std::max(dx, (int)(-width *0.5));

    int dy = std::min(circleY, (int)(height * 0.5));
    int dy1 = std::max(dy, (int)(-height * 0.5));

    return (dx1 - circleX) * (dx1 - circleX) 
           + (dy1 - circleY) * (dy1 - circleY) <= radius * radius;
}


bool Collision(int circleX, int circleY, int radius, 
               int squareX, int squareY, int width, int height)
{

    //get center of square
    int center_of_square_x = squareX + width/2;
    int center_of_square_y = squareY + height/2;

    //if square is already at origin, test directly
    if ( center_of_square_x == 0 && center_of_square_y ==0)
    {
        return testForCollision(circleX, circleY, width, height, radius);
    }
    else
    {
        //shift center of square to origin and update coordinates of circle
        //only consider part of the situation, more to add about shifting
        circleX = circleX - center_of_square_x;
        circleY = circleY - center_of_square_y;
        return testForCollision(circleX, circleY, width, height, radius);
    }
}

这样,它应该能够识别圆形和正方形是否相互碰撞。

编辑:让我们通过一个测试用例:

circleX = 60 circleY = 172 radius = 39
squareX = 120 squareY = 180 width = 72 height = 72 

我们有正方形的坐标如下(包括中心)

120, 252  -------- 192, 252
 |                   |
 |--------156,216----|
 |                   |
120,180   ---------192,180

我们可以看到 (60,172) 位于边缘 (120,252)-->(120,180) 的左侧,(120,180) 和 (60,72) 之间的距离大于 39。 (120,252) 和 (60,72) 之间的距离也大于39,没有重叠。为了更好地理解它,给定圆心 (60,172) 和半径 39,您可以从圆心到达的 x 和 y 范围是 (60-39,60 +39) = (21,99) 和 ( 172-39, 172+39) = (133,211)。如果您将其可视化,这应该与正方形没有重叠。

如果您首先将原点转换为 (156,216),我们将 (-96,-44) 作为新坐标系中的圆心。它位于第三象限。如果您运行 testForCollision 函数,您将看到没有重叠。

dx = min(-96,36) = -96
dx1 = max(dx, -36) = -36
dy = min(-44, 36) = -44
dy1 = max(dy,-36) = -36

distance = (-36 - (-96))^2 + (-36 - (-44))^2 = 60^2 + 8^2 > 39^2, so no overlap
于 2013-04-14T02:15:39.380 回答
2

有3种情况:

  • 形状重叠,因此一个形状的边缘穿过另一个形状的边缘
  • 圆圈完全在正方形内(例如,想象在某处有一个小圆圈的巨大矩形)
  • 完全在圆圈内的矩形(例如,想象一个带有小矩形的巨大圆圈)

首先确定圆心到矩形中心的距离。我们称这个距离为 D。

然后找到足够小以适合矩形的最大圆圈。这将具有等于矩形高度或矩形宽度(以较小者为准)的直径。如果新圆的半径加上原圆的半径小于距离D,那么肯定有碰撞。

然后找到足够大以包含整个矩形的最小圆。这个圆的半径可以用毕达哥拉斯找到(从矩形中心到矩形任意角的距离)。如果这个新圆的半径加上原圆的半径大于距离D,那么就不可能发生碰撞。

如果这两个测试都没有给你答案;那么两个形状都不完全在另一个形状内,但它们可能重叠或不重叠;因此您必须确定一个形状的边缘是否与另一个形状的边缘相交。为此,扩展矩形的所有边缘,使其无限长(使用线段来描述一条线);并尝试通过将 x 或 y “插入”到圆的公式中来计算这些无限长的线与圆的圆周相交的位置(注意:您会发现没有交点、1 个交点或 2 个交点)。如果有 2 个交叉点,则必须测试其中一个是否是边缘。

例如,如果您的矩形的顶部边缘在y = 2您的正前方,您将插入y = 2一个圆形。如果您发现这条线x = 3在 x = 6` 处相交,然后测试 3 和 6 是否都在矩形的左边缘和矩形的右边缘之间 - 如果它们是,那么圆的边缘与矩形的顶部边缘,你有一个碰撞。

如果您对矩形的所有 4 个边缘进行“边缘相交”测试而没有检测到碰撞,那么就不会检测到碰撞。

于 2013-04-14T03:34:09.067 回答