如何检测在线碰撞中的2D线?


13

我是一名Flash动作脚本游戏开发人员,他对数学有些落后,尽管我发现物理学既有趣又很酷。

作为参考,这是与我正在制作的游戏类似的游戏:纠结的Flash游戏

我已经使这个复杂的游戏几乎完全完成了逻辑。但是,当两条线相交时,我需要那些相交或“缠结”的线来显示不同的颜色。红色。

如果您可以提出一种检测线段碰撞的算法,那对您来说真的非常好。我基本上是一个喜欢“视觉上”而非“算术上”思考的人:)

编辑:我想添加一些图表,以使想法更清晰地传达

没有路口 没有路口 路口 没有路口

PS我正在尝试使功能

private function isIntersecting(A:Point, B:Point, C:Point, D:Point):Boolean

提前致谢。


6
这是对该问题的令人失望的非视觉解释,但它是一种算法,并且如果您可以使自己阅读他们的数学知识,那么这是有道理的:local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d如果您的向量数学很弱,那就沉重。我了解-我也更喜欢视觉上的解释。我会在以后尝试找些时间做些涂鸦,但是如果某个人出于艺术上的偏见看到了此链接并且有时间在我面前,那就快点开始吧!
安科2012年

Answers:


18

我使用以下方法,该方法几乎只是该算法的一种实现。它在C#中,但是将其翻译为ActionScript应该很简单。

bool IsIntersecting(Point a, Point b, Point c, Point d)
{
    float denominator = ((b.X - a.X) * (d.Y - c.Y)) - ((b.Y - a.Y) * (d.X - c.X));
    float numerator1 = ((a.Y - c.Y) * (d.X - c.X)) - ((a.X - c.X) * (d.Y - c.Y));
    float numerator2 = ((a.Y - c.Y) * (b.X - a.X)) - ((a.X - c.X) * (b.Y - a.Y));

    // Detect coincident lines (has a problem, read below)
    if (denominator == 0) return numerator1 == 0 && numerator2 == 0;

    float r = numerator1 / denominator;
    float s = numerator2 / denominator;

    return (r >= 0 && r <= 1) && (s >= 0 && s <= 1);
}

但是,该算法存在一个细微的问题,即两行重合但不重叠的情况。在这种情况下,算法仍返回交集。如果您关心这种情况,我相信关于stackoverflow的答案有一个更复杂的版本可以解决。

编辑

对不起,我没有从该算法得到结果!

奇怪,我已经对其进行了测试,除了上面描述的单个案例外,它对我来说都是有效的。使用我上面发布的完全相同的版本,在将其用于测试驱动器时得到了以下结果:

在此处输入图片说明


对不起,我没有从该算法得到结果!
毗湿奴(Vishnu)

4
@Vish您遇到什么问题?在发布之前,我测试了该算法的确切副本,除描述的单个情况外,它均能完美工作。
David Gouveia 2012年

然后,让我再试一次,我可能在其中混入了一些数学运算。我会尽快通知您。谢谢,无论如何:)
Vishnu

1
我从您的算法中获得了理想的结果,谢谢@DavidGouveia。
毗湿奴(Vishnu)

1
好吧,但是现在我有另一个问题:)!我需要用红色和绿色制作相交的线。交叉路口工作正常。但是,正如我现在所了解的(尽管不是数学上的),简单的if-else不能将红色和绿色线用于相交线和非相交线。我要拖动的节点同时具有左右两边的线。因此,在将未相交的线条的颜色更改回绿色时,某处出现了问题。我想我也需要其他条件。嗯,无论如何,还是要多谢我将其标记为正确的答案。
Vishnu

4

没有分裂!因此,精度或除以零都没有问题。

线段1是A到B线段2是C到D

线是一条永无止境的线,线段是该线的定义部分。

检查两个边界框是否相交:如果没有相交->没有交叉!(计算完成,返回false)

检查线段1是否跨过线段2,线段2是否跨过线段1(即线段1在线段2定义的线的两侧)。

这可以通过用-A平移所有点来完成(即,您移动了2条线,因此A在origo(0,0)中)

然后检查点C和D是否在由0,0到B定义的线的不同侧

//Cross Product (hope I got it right here)
float fC= (B.x*C.y) - (B.y*C.x); //<0 == to the left, >0 == to the right
float fD= (B.x*D.y) - (B.y*D.x);

if( (fc<0) && (fd<0)) //both to the left  -> No Cross!
if( (fc>0) && (fd>0)) //both to the right -> No Cross!

如果您还没有“ No Cross”,那么继续使用而不是A,B与C,D,而是C,D与A,B(相同的计算,只需交换A和C,B和D),如果没有“没有十字架!” 那么你有一个十字路口!

我搜索了叉积的精确计算,并找到了该博客文章,其中也介绍了该方法。


1
抱歉,我对矢量数学不太满意,我实现了这种算法,但没有结果,抱歉!
毗湿奴(Vishnu)

1
它应该可以工作,所以也许如果您可以向我们展示您的代码,我们可以在那里帮助您?
Valmond 2012年

真好!但是链接断开了
clabe45 '18

您可以添加一些东西以获得交叉点吗?
SeanRamey19年

1

我只想说,我的Gamemaker Studio游戏需要它,而且效果很好:

///scr_line_collision(x1,y1,x2,y2,x3,y3,x4,y4)

var denominator= ((argument2 - argument0) * (argument7 - argument5)) - ((argument3 - argument1) * (argument6 - argument4));
var numerator1 = ((argument1 - argument5) * (argument6 - argument4)) - ((argument0 - argument4) * (argument7 - argument5));
var numerator2 = ((argument1 - argument5) * (argument2 - argument0)) - ((argument0 - argument4) * (argument3 - argument1));

// Detect coincident lines
if (denominator == 0) {return (numerator1 == 0 && numerator2 == 0)}

var r = numerator1 / denominator;
var s = numerator2 / denominator;

return ((r >= 0 && r <= 1) && (s >= 0 && s <= 1));

我认为,如果您解释了代码的作用,那么此答案可能会真正改善。
TomTsagk

1

在这种情况下,可接受的答案给出了错误的答案:

x1 = 0;
y1 = 0;
x2 = 10;
y2 = 10;

x3 = 10.1;
y3 = 10.1;
x4 = 15;
y4 = 15;

这些线显然不相交,但是根据“正确答案”中的功能,这些线确实相交。

这就是我用的:

function do_lines_intersect(px1,py1,px2,py2,px3,py3,px4,py4) {
  var ua = 0.0;
  var ub = 0.0;
  var ud = (py4 - py3) * (px2 - px1) - (px4 - px3) * (py2 - py1);


  if (ud != 0) {
    ua = ((px4 - px3) * (py1 - py3) - (py4 - py3) * (px1 - px3)) / ud;
    ub = ((px2 - px1) * (py1 - py3) - (py2 - py1) * (px1 - px3)) / ud;
        if (ua < 0.0 || ua > 1.0 || ub < 0.0 || ub > 1.0) ua = 0.0;
  }

  return ua;
}

返回0 =线不相交

返回> 0 =线相交


更新以回答问题:

我不是自己创建此代码的。它已经超过5年了,我不知道原始来源是什么。但..

我认为返回值是它们相交的第一行的相对位置(不好解释)。要计算相交点,您可以使用lerp,如下所示:

l = do_lines_intersect(...)
if (l > 0) {
    intersect_pos_x = l * (px2-px1);
    intersect_pos_y = l * (py2-py1);
} else {
    // lines do not cross
}

(我没有对此进行测试)


是否有返回交点的版本?
SeanRamey19年
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.