任意大小凸多边形碰撞检测算法

时间:2013-01-31 16:04:34

标签: c++ algorithm 2d collision-detection

我正在研究小行星克隆。一切都是2D,用C ++编写。

对于小行星,我正在生成随机的N边多边形。我保证他们是Convex。然后我旋转它们,让它们旋转速度,让它们飞过太空。一切正常,非常漂亮。

对于碰撞,我使用的是我自己想到的算法。这可能是一个坏主意,如果推动,我可能会废弃整个事情并在互联网上找到一个教程。

我已经编写并实现了所有内容,并且碰撞检测工作正常....大部分时间。当屏幕上明显发生碰撞时,它会随机失败,有时会在没有任何触摸时指示碰撞。我要么在某处扯下我的实现,要么我的算法很糟糕。由于我的实现的大小/范围(通过几个源文件),我不想打扰你,只是想让某人检查我的算法实际上是合理的。那时我可以继续寻找一个大虫子。

算法:

对于每个小行星,我有一个函数,在绘制小行星时输出每个顶点的位置。对于每对相邻的顶点,我为它们所在的行生成公式y=mx+b格式。然后我从我的一个船顶点开始,测试该点以查看它是否在小行星内。我首先插入点的X坐标,然后将输出与实际Y值进行比较。这告诉我该点是在线之上还是之下。然后我对小行星的中心做同样的事情,以确定哪一半的线被认为是小行星的“内部”。然后我重复每对顶点。如果我找到一条线,我的点与小行星的中心不在同一侧,我知道没有碰撞,并且退出检测到该点。由于我的船上有3个点,我必须测试下一个点。如果所有3个点都提前退出,那么船上的任何一点都没有碰撞,我们就完成了。如果任何一点被小行星组成的线束在所有边上,那么它就在小行星内,并设置了碰撞标志。

我用这个算法发现的两个问题是:

  1. 它不适用于凹多边形,
  2. 在Slope未定义的Edge情况下出现问题。
  3. 我已经确保所有多边形都是凸面的,并且已经编写了代码来处理未定义的斜率问题(如果我们除以NAN,则双重应该返回0,因此测试它非常容易)

    那么,这应该有效吗?

2 个答案:

答案 0 :(得分:7)

该问题的标准解决方案是使用分离轴定理(SAT)。给定两个凸多边形A和B,算法基本上如下:

for each normal N of the edges of A and B
    intervalA = [min, max] of projecting A on N
    intervalB = [min, max] of projecting B on N
    if intervalA doesn't overlap intervalB
        return did not collide
return collided

答案 1 :(得分:2)

我做了类似于计算多边形交叉点的操作,即查找顶点是否位于给定的多边形内。

你的算法是合理的,实际上对于凹多边形也不起作用。您选择的线表示在接近无穷大的斜率上也存在问题。我选择使用几个向量,一个用于线方向,一个用于线上的参考点。通过这些,我可以很容易地得到线的参数化方程,并以各种方式使用它来找到其他形状的交叉点。

P = S +  t * D

在给定上述关系的情况下,线的任何点P都可以通过线上的坐标t来表征,其中S是参考点,D是方向矢量。

这种表示方式可以让您轻松定义平面的哪些部分是正面和负面部分(即线的上方和下方),这要归功于方向方向。现在,平面的任何区域都可以定义为几条线的负或正子平面的交点。所以你的“多边形点”算法可以略微改变以使用该表示,所有方向的附加约束顺时针方向,并测试所有线的负底平面中的点(所以你不需要多边形的中心了。)

计算我使用的一条点的边的公式如下:

(xs - xp) * yd - (ys - yp) * xd

当P点接近S时,斜率问题出现在这里。

可以使用边缘顶点计算该表示,但是为了具有正确的子平面,您必须以连续的顺序将顶点保持在多边形中。

对于凹多边形,问题有点复杂:简而言之,您必须测试该点位于两个连续凸边之间。这可以通过在投影到边缘上时检查边缘上的点的坐标来确定,并确保它位于0length(edge)之间(假设方向已标准化)。请注意,它可以归结为检查点是否属于多边形内的三角形。