这篇文章虽然有些陈旧,但仍然很有参考价值。对于整体形状不变的多边形(可以旋转和缩放,但顶点之间的关系不能改变),有一些方法可以预处理顶点数据,以实现对多边形中的线进行一系列测试,以测试其他多边形是否与其碰撞。
我正在编写这个算法,所以我将向您提供其理论而非现成的算法:
传说:&&表示AND,||表示OR。
第一步a:
遍历多边形的线,并将每条线与其所有其他点进行测试,我们将分离出所有其他点位于该线上或“内部”一侧的线。
这些收集到的线形成了碰撞检测公式中的一个新节点,它们在彼此之间被视为逻辑AND检查。
第一步b:
将每个孤立的顶点组分别分离出来,并将它们单独馈送到下一步骤中:这些孤立的顶点组在彼此之间被视为逻辑AND。
第一步c:
如果在第3a/3b步到达时收集了任何线条,并且由于需要进入1a步骤而同时收集了多条线条,请重置在步骤3a / 3b中设置的任何变量并直接返回1a步骤。
第二步a:
遍历多边形的线,并将每条线与其所有其他点进行测试,我们将分离出所有其他点位于多边形的“外侧”(或更具体地说,全部位于线的非碰撞侧)的线。
这些收集到的线形成了碰撞检测公式中的一个新节点,它们在彼此之间被视为逻辑OR检查。
第二步b:
将每个孤立的顶点组分别分离出来,并将它们单独馈送到下一步骤中:这些孤立的顶点组在彼此之间被视为逻辑OR。
第二步c:
如果在第2a步骤中收集了任何线条,请重置在步骤3a / 3b中设置的任何变量并直接返回1a步骤。
第三步a:
进入此阶段意味着没有线条剩余,所有顶点都位于其中一条线的一侧。这意味着我们需要更积极地收集线条:
提高在步骤1a和2a中要收集的连续线条数量。这意味着除了所有顶点都位于一条线的一侧之外,它们必须至少位于收集到的线条之一的一侧(在1a中为内侧,在2a中为外侧)。一旦收集到任何线条,此值将重置为1。
第三步b:
如果要收集的连续线的数量超过图形中的线条数量,则将数字重置为2并允许收集非连续的线条(到达此处也是您的网格有点复杂并且您可能需要考虑将其缩小一点,不过达到3a并不是大问题,因为简单的星形必须输入才能解决)。
当使用生成的节点进行碰撞测试时,只需按顺序将要测试对象(点/线/圆)的形状提供给处理后的网格中的节点即可。
对于要进行碰撞测试的两个多边形,只需对其中一个进行此类处理。
创建示例多边形的公式:
1)将示例多边形提供给步骤1a:
在1a步骤之后的示例多边形
图片中的红线是所有其他顶点都在其内部的线,因此必须在其中找到一个形状以使其能够与多边形发生碰撞。
在1b之后,多边形将分为两个岛屿(A和B)。
2)将A和B提供给步骤2a:
在2a步骤之后的示例多边形
图片中的绿线是所有其他顶点都在其外部的线,因此如果形状在其中之一内部,则碰撞将发生。
在2b之后,A和B岛屿将进一步分为C、D、E和F。
3)将C、D、E和F提供给步骤1a:
在1a步骤之后的示例多边形
多边形C将失去一条线(我们称新形状为G),D将在1b步骤后分为两个岛屿(H和I),而多边形E和F没有线条可收集。
4)将G、H和I提供给步骤2a:
在2b步骤之后的示例多边形
多边形G将在2c步骤后分为两个岛屿(J和K),H将失去2条线(称新形状为L),而I将没有线条可收集。
5)将J、K和L提供给步骤1a:
在1a步骤之后的示例多边形
完成后,只需重复这些步骤3次即可收集到所有线条。
最终的多边形公式如下所示:
已标注相位的一行最终公式
更直观的表示方法如下:
带有可视化表示的最终公式
以下是标记了线条的原始多边形:
标记了线条的多边形
使用此方法,凹多边形测试碰撞的速度与将其分解为凸多边形时相同甚至更快(最坏情况是如果两者具有相同数量的顶点,则需要相同的时间,最佳情况可以将测试缩短到步骤1中的所有线和步骤2中的一条线,如果发生碰撞,则可以切掉形状的任何更复杂的蜿蜒线路)。
此算法的限制至少包括以下内容:
1)如果多边形的顶点正在进行动画处理,则上述公式不再适用,并且必须重新制作。然而,对于数量不太复杂的小型多边形来说,上述步骤并不是很复杂(需要(n-2)^2个“这个点在这条线的哪一侧”测试-其结果可以在整个步骤中被缓存和重用)。
2)不会自动处理多边形中的孔。然而,可以像上面那样处理孔并将以下规则应用于它:与原始多边形发生碰撞的形状必须与孔的线相交或者不与孔多边形发生碰撞才能发生碰撞。
3)我提出的拆分多边形的规则未针对任意复杂的多边形进行测试,并且可能需要进一步的规则来处理它们。
4)你必须自己编写算法的代码,因为我没有打算发布一个工作通用版本,这可能需要一段时间。