JavaScript中线段和圆的碰撞检测

7
我正在寻找一个确定的答案,可能是一个函数,因为我很慢,它将确定在javascript中(使用canvas)线段和圆是否发生碰撞。像下面这样的一个函数,如果发生碰撞则简单地返回true,如果没有发生碰撞则返回false,那就太棒了。我甚至可能会把我的孩子捐给你。
function isCollided(lineP1x, lineP1y, lineP2x, lineP2y, circlex, circley, radius) {

    ...
}

我发现了许多公式,例如这个,但是它们超出了我的理解范围。

1
即使您没有理解数学,答案中提供的代码也应该对您有用。 - Oliver Charlesworth
4
这正是你高中代数学习所派上用场的时刻。 - Derek 朕會功夫
1
@Derek:同意。现在我30岁了,开始秃头,什么都没有。 - Jarrod
1
事实:圆的公式为:(x−h)^2+(y−k)^2=r^2,直线的公式为:y=a+bx。如果您能解决这两个公式,并且得到一个答案,那么就存在碰撞。 - Derek 朕會功夫
但是这只是它,(x−h)^2+(y−k)^2=r^2 对我来说毫无意义。 - Jarrod
显示剩余2条评论
4个回答

8

在这里,您需要一些数学知识:

enter image description here 如果您不知道如何解决方程式,这是基本概念。我会把剩下的思考留给您。 ;) 找出CD的长度并不难。

如果您想知道如何找到CD的长度,就是这样: enter image description here 在JavaScript中查找碰撞有些复杂。


1
不错的图形,伙计!@Jarrod:减去数字不应该是问题,所以我猜你的问题在于三角学/向量?关于这方面有很多信息在互联网上,我怀疑为了这个问题特别总结它并不明智。 - Niklas B.
1
(或者简单地使用“Math.atan((m1 - m2)/(1 + m1*m2))”,其中“m”是斜率) - Derek 朕會功夫
1
不要感到惊讶,如果你发现角度看起来不对,因为在JavaScript中所有的角度都是以弧度而非度数表示。 - Derek 朕會功夫
谢谢!但是如何计算反弹/解决碰撞呢?我的意思是,设置圆的新位置和速度? - user2039981
@Murplyx - 我对物理不是很了解,但你可以计算碰撞的确切点。也许这可以帮助你? - Derek 朕會功夫
显示剩余3条评论

4

我花了大约一天半的时间来使它完美...希望这可以帮到你。

function collisionCircleLine(circle,line){ // Both are objects

    var side1 = Math.sqrt(Math.pow(circle.x - line.p1.x,2) + Math.pow(circle.y - line.p1.y,2)); // Thats the pythagoras theoram If I can spell it right

    var side2 = Math.sqrt(Math.pow(circle.x - line.p2.x,2) + Math.pow(circle.y - line.p2.y,2));

    var base = Math.sqrt(Math.pow(line.p2.x - line.p1.x,2) + Math.pow(line.p2.y - line.p1.y,2));

    if(circle.radius > side1 || circle.radius > side2)
        return true;

    var angle1 = Math.atan2( line.p2.x - line.p1.x, line.p2.y - line.p1.y ) - Math.atan2( circle.x - line.p1.x, circle.y - line.p1.y ); // Some complicated Math

    var angle2 = Math.atan2( line.p1.x - line.p2.x, line.p1.y - line.p2.y ) - Math.atan2( circle.x - line.p2.x, circle.y - line.p2.y ); // Some complicated Math again

    if(angle1 > Math.PI / 2 || angle2 > Math.PI / 2) // Making sure if any angle is an obtuse one and Math.PI / 2 = 90 deg
        return false;


        // Now if none are true then

        var semiperimeter = (side1 + side2 + base) / 2;

        var areaOfTriangle = Math.sqrt( semiperimeter * (semiperimeter - side1) * (semiperimeter - side2) * (semiperimeter - base) ); // Heron's formula for the area

        var height = 2*areaOfTriangle/base;

        if( height < circle.radius )
            return true;
        else
            return false;

}

这就是你如何做到它。


2
“这就是你要做的方式…” 但这并不是你回答问题的方式。开个玩笑,加一些上下文来支持你的代码伙计。简单地发布一些代码并不是一个好的回答方式。 - Harshith Rai
我不知道这是否有效,但 Math.atan2 需要先输入 y 再输入 x,你把它反了。 - Pattycake Jr

1

0
function pointCircleCollide(point, circle, r) {
    if (r===0) return false
    var dx = circle[0] - point[0]
    var dy = circle[1] - point[1]
    return dx * dx + dy * dy <= r * r
}

var tmp = [0, 0]

function lineCircleCollide(a, b, circle, radius, nearest) {
    //check to see if start or end points lie within circle
    if (pointCircleCollide(a, circle, radius)) {
        if (nearest) {
            nearest[0] = a[0]
            nearest[1] = a[1]
        }
        return true
    } if (pointCircleCollide(b, circle, radius)) {
        if (nearest) {
            nearest[0] = b[0]
            nearest[1] = b[1]
        }
        return true
    }

    var x1 = a[0],
        y1 = a[1],
        x2 = b[0],
        y2 = b[1],
        cx = circle[0],
        cy = circle[1]

    //vector d
    var dx = x2 - x1
    var dy = y2 - y1

    //vector lc
    var lcx = cx - x1
    var lcy = cy - y1

    //project lc onto d, resulting in vector p
    var dLen2 = dx * dx + dy * dy //len2 of d
    var px = dx
    var py = dy
    if (dLen2 > 0) {
        var dp = (lcx * dx + lcy * dy) / dLen2
        px *= dp
        py *= dp
    }

    if (!nearest)
        nearest = tmp
    nearest[0] = x1 + px
    nearest[1] = y1 + py

    //len2 of p
    var pLen2 = px * px + py * py

    //check collision
    return pointCircleCollide(nearest, circle, radius)
            && pLen2 <= dLen2 && (px * dx + py * dy) >= 0
}

var circle = [5, 5],
    radius = 25,
    a = [5, 6],
    b = [10, 10]

var hit = lineCircleCollide(a, b, circle, radius)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接