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

Algorithms for Collision Detection between Arbitrarily sized Convex Polygons

本文关键字:碰撞检测 算法 之间 凸多边形 任意大      更新时间:2023-10-16

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

对于小行星,我正在生成随机的N边多边形。我保证它们是凸面的。然后我旋转它们,给它们一个旋转速度,让它们在太空中飞行。一切都很好,而且非常漂亮。

对于碰撞,我使用了一个我自己认为的算法。这可能是个坏主意,如果事态发展到紧要关头,我可能会放弃整个想法,在网上找一个教程。

我已经编写并实现了所有内容,碰撞检测工作正常。。。。大多数时候。当屏幕上有明显的碰撞时,它会随机失效,有时当没有任何东西接触时,它也会指示碰撞。要么我在某个地方搞砸了我的实现,要么我的算法太糟糕了。由于我的实现的大小/范围(在几个源文件上(,我不想为此打扰你,只想有人检查一下我的算法是否正确。到那时,我可以进行一次大规模的昆虫狩猎。

算法:

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

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

  1. 它不适用于凹多边形,并且
  2. 对于"未定义坡度"的"边"情况,它存在问题

我已经确保所有多边形都是凸的,并编写了处理未定义斜率问题的代码(如果我们除以0,则doubles应该返回NAN,所以测试这一点非常容易(。

那么,这应该奏效吗?

这个问题的标准解决方案是使用分离轴定理(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

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

您的算法是合理的,并且确实不适用于凹多边形。在接近无穷大的坡度上,您选择的线表示也有问题。我选择使用两个矢量作为我的矢量,一个用于直线方向,另一个用于线上的参考点。从中,我可以很容易地导出一个参数化的直线方程,并以各种方式使用它来找到与其他形状的交点。

P = S +  t * D

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

通过此表示,您可以很容易地定义平面的哪些部分是正部分和负部分(即线的上方和下方(,这要归功于方向方向。现在,平面的任何区域都可以定义为几条线的负子平面或正子平面的交点。因此,您的"多边形内的点"算法可以稍微更改以使用该表示法,添加所有方向都指向顺时针的约束,并测试点是否位于所有线的负子平面中(这样您就不再需要多边形的中心(。

我使用的计算点与线的边的公式如下:

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

当点p接近S.时,斜率问题出现在此处

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

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