曲线碰撞检测


12

我正在开发2D游戏,其中我想在运动的圆和某种静态曲线(可能是贝塞尔曲线)之间进行碰撞检测。

目前,我的游戏仅以直线作为静态几何图形,并且我正在通过计算从圆到线的距离进行碰撞检测,并在距离小于圆半径的情况下将圆投影到线外。

如何以相对简单的方式进行这种碰撞检测?例如,我知道Box2D具有Bezier曲线的碰撞检测功能。我不需要功能齐全的碰撞检测机制,只需执行我描述的操作即可。


更新:非常感谢您的出色回答!我必须阅读Bezier曲线才能完全理解您所描述的方法。那我会回覆您。

Answers:


6

29/09/2012-23:20

我在这里创建了一个git仓库:https : //github.com/ArthurWulfWhite/Bezier-Distance/

欢迎您从此处以zip格式下载源文件。它还包括一个可以使用FlashDevelop进行编译的演示。要使用该演示,请在Flash Develop中打开项目,然后单击“测试项目”。在运行演示时,单击LMB随机分配新的Bezier曲线和新的Circle。

祝好运!

zip链接很难看到-只需使用Ctrl + F并键入zip。该资源代表了数周的研究和编程,希望您喜欢。


如果计划将贝塞尔曲线递归地划分为多个段并检查与它们的碰撞,我建议制作一个100,100的阵列(网格)并将每个段放置在四个最近的正方形中,因此您只需要检查与4 / 10,000的碰撞细分每帧。

我确实认为,无论是作为程序员还是作为游戏创造者,您都将从box2d中受益,因为制作“简单的”物理引擎时存在许多隐藏的小障碍,使运动看起来有些坎and,流动性也比以前少。

旧答案:纯粹的方法。

通过检查圆心和曲线上最接近点之间的距离,您实际上可以查看圆是否与贝塞尔曲线发生碰撞。

距离方程(一般)

解释:

贝塞尔公式:

q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))

可以总结为(含一些代数)-为了可读性,我将省略。(x,y)(它们仍然是点,而不是一个数字)

q(t) = (start -2 * cont + end) t^2 + (-2 * start + 2 * control) + start

距点(x,y)的距离为:

sqrt ((q(t).x - point.x)^2 + (q(t).y - point.y)^2)

要在贝塞尔曲线上找到最接近球的点,您需要导出并找到导数等于零(根)的所有点。它是三次的多项式,因此您可以使用封闭式,但是由于计算机浮点表示的分数的精度可能不够,因此可能不可靠。最好使用牛顿或类似性质的东西。

您需要找到其根的导数是:

假设:a =开始b =控制c =结束d =圆心

使用Wolfram alpha的导数

棘手的部分是将这一点相乘,您必须使用点积。

如果您愿意,我有相应的代码,可以在这里以函数的形式共享它,该函数可以简单地返回一个布尔值(如果有无碰撞和碰撞角度)。在像这样的碰撞引擎的幼稚实现中可能会出现一些问题,例如,快速移动的球可能会卡在两条曲线之间。

我建议暂时不要使用它,只需将x轴和y轴的系数求和并相加即可。

使用您可以选择的任何可靠方法,例如Newton来找到根,检查从贝塞尔曲线的根点到0 <= t <= 1到圆心的距离,并检查贝塞尔曲线两端的距离(开始和结束)到圆心,以最接近的那个为准,它会告诉您是否发生碰撞。

如果半径小于最小距离,则发生碰撞。

该角度大约是圆心和贝塞尔曲线上最接近点之间的角度。

话虽这么说,如果您真的想用碰撞物理学来制作游戏,我建议您迭代贝塞尔曲线

    q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))

将每个片段递归地划分到中间,直到足够小(可以说10像素或更小),然后从盒子中大致构建贝塞尔曲线,并将Box2d用于物理上,因为编写所有这些碰撞检测代码可能被证明是很棒的时间消耗并不能改善游戏玩法。过去,Box2d的使用已在无数项目中得到证明。


您描述的计算曲线最短点的方法恰好是我当前使用的是线而不是曲线的方法。但是用您解释的方法对曲线进行相同的操作听起来有点复杂。据我了解,这也是您的想法。关于Box2D。我相信这是一项很棒的工作。但是说实话,我的游戏中的物理过程非常简单,因此,我认为完全使用物理引擎是过分的。
paldepind 2012年

您的游戏中有多少个物体?可以相互碰撞多少?有时,使用物理引擎可以产生巨大的好处,例如它可以准确地计算碰撞时间。(因为帧是离散的,并且碰撞是真实的(渲染帧时不会精确发生)
AturSams 2012年

实施新事物和使用2D物理api的好处时,通常比预料不到的挑战是,就像使用任何编程语言一样,除了投入数小时的时间来学习它并不需要付出额外的努力,结果非常令人满意。
AturSams 2012年

我现在添加了一些详细信息,祝您好运。:)
AturSams 2012年

我正在创建一个简单的类似《 Elasto Mania》的游戏。只有三个运动的圆和静态几何。整个引擎已经完成并且运转良好。唯一剩下的就是允许曲线,这要归功于此答案中的帮助:)我可以解决atm的问题:)随时发布您提到的代码。您认为在现实生活中使用它有多合适?比将贝塞尔曲线转换成细线更好?
paldepind 2012年

7

为此,我将:

  • 将贝塞尔曲线折成几条线段并存储。

  • 将所有这些线段放在整个曲线的轴对齐边界框中。

碰撞检测 :

1)检查球体是否在主边界框内。如果没有,则没有碰撞。

2)否则,检查上面计算出的任何单个线段是否与球体发生碰撞。请参阅Wikipedia中的线-球相交的文章

编辑:如果需要高精度并希望获得良好的性能,则还可以为整个曲线创建一个主边界框,然后将曲线细分为两段(例如:[0.0 - 0.5][0.5 - 1.0])。创建为他们每个人的bouding框,然后再细分每个段的两段(从而使[0 - 0.25][0.25 - 0.5][0.5 - 0.75][0.75 - 1.0])。继续这样,直到达到足够的精度。最后,您将有一个binary tree边界框,在根部有主曲线边界框,在叶子处有线段。在树中搜索将为您O(log n)提供O(n)(而不是(其中n=曲线的线段数))


该解决方案对我来说很有意义,而且绝对是最容易理解的解决方案,我可能会接受。但是我很好奇是否存在更“纯”的选择。
paldepind 2012年

5

线与贝塞尔曲线之间的交点是通过对曲线进行细分而在数学上实现的。这意味着依赖于曲线的凸包属性,并以类似“分割等距”的方式将其分成具有不同控制多边形的较小弧。

本文涵盖了这一点:http : //students.cs.byu.edu/~tom/557/text/cic.pdf

最棒的是,该算法可与任何直线配合使用,您只需对曲线应用刚性变换,即可将目标直线视为与Ox轴平行。

同样,将贝塞尔曲线弧细分为两个子弧时,可以检查每个这样的贝塞尔曲线弧的圆和多边形。圆应与圆弧的控制多边形相交,以便进行曲线到圆测试。


我还没有看过这篇文章。但是,如何从直线和贝塞尔曲线之间的交点到圆与贝塞尔曲线之间的交点呢?对一个圆和一个多边形检查碰撞听起来对我来说有点复杂。
paldepind 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.