多边形碰撞检测实现

4
我正在尝试编写自己的分离轴定理实现,但是我在让它像我想要的那样准确工作方面遇到了一些问题。我不能确定,但看起来它在像第一个形状中与形状周围的虚拟框发生碰撞时会报告碰撞。但第二个形状运行得非常完美。
这是正方形的顶点数据(精确坐标):
vertsx = [ 200, 220, 220, 200 ]
vertsy = [ 220, 220, 200, 200 ]

这是测试形状1的顶点数据(相对于鼠标):

vertsx = [ -10,   0,  10, 10, -10 ]
vertsy = [ -10, -50, -10, 10,  10 ]

最后,这是测试形状2的顶点数据(相对于鼠标):
vertsx = [ -10,   0,  10, 10, -10 ]
vertsy = [ -10, -20, -10, 10,  10 ]

为了澄清,翻译后的坐标是被测试过的,并且这些形状已经按照所示顺序对坐标进行了测试。

enter image description here

这是实际的函数。

function collisionConvexPolygon ( vertsax, vertsay, vertsbx, vertsby ) {
    var alen = vertsax.length;
    var blen = vertsbx.length;
    // Loop for axes in Shape A
    for ( var i = 0, j = alen - 1; i < alen; j = i++ ) {
        // Get the axis
        var vx =    vertsax[ j ] - vertsax[ i ];
        var vy = -( vertsay[ j ] - vertsay[ i ] );
        var len = Math.sqrt( vx * vx + vy * vy );

        vx /= len;
        vy /= len;

        // Project shape A
        var max0 = vertsax[ 0 ] * vx + vertsay[ 0 ] * vy, min0 = max0;
        for ( k = 1; k < alen; k++ ) {
            var proja = vertsax[ k ] * vx + vertsay[ k ] * vy;

            if ( proja > max0 ) {
                max0 = proja;
            }
            else if ( proja < min0 ) {
                min0 = proja;
            }
        }
        // Project shape B
        var max1 = vertsbx[ 0 ] * vx + vertsby[ 0 ] * vy, min1 = max1;
        for ( var k = 1; k < blen; k++ ) {
            var projb = vertsbx[ k ] * vx + vertsby[ k ] * vy;

            if ( projb > max1 ) {
                max1 = projb;
            }
            else if ( projb < min1 ) {
                min1 = projb;
            }
        }
        // Test for gaps
        if ( !axisOverlap( min0, max0, min1, max1 ) ) {
            return false;
        }
    }
    // Loop for axes in Shape B (same as above)
    for ( var i = 0, j = blen - 1; i < blen; j = i++ ) {
        var vx =    vertsbx[ j ] - vertsbx[ i ];
        var vy = -( vertsby[ j ] - vertsby[ i ] );
        var len = Math.sqrt( vx * vx + vy * vy );

        vx /= len;
        vy /= len;

        var max0 = vertsax[ 0 ] * vx + vertsay[ 0 ] * vy, min0 = max0;
        for ( k = 1; k < alen; k++ ) {
            var proja = vertsax[ k ] * vx + vertsay[ k ] * vy;

            if ( proja > max0 ) {
                max0 = proja;
            }
            else if ( proja < min0 ) {
                min0 = proja;
            }
        }
        var max1 = vertsbx[ 0 ] * vx + vertsby[ 0 ] * vy, min1 = max1;
        for ( var k = 1; k < blen; k++ ) {
            var projb = vertsbx[ k ] * vx + vertsby[ k ] * vy;

            if ( projb > max1 ) {
                max1 = projb;
            }
            else if ( projb < min1 ) {
                min1 = projb;
            }
        }
        if ( !axisOverlap( min0, max0, min1, max1 ) ) {
            return false;
        }
    }
    return true;
}

我会尝试其他形状,如果你需要的话。
这是我的axisOverlap函数。
function axisOverlap ( a0, a1, b0, b1 ) {
    return !( a0 > b1 || b0 > a1 );
}

你能同时发布你的 axisOverlap() 函数吗? - techfoobar
请尝试一下不翻转vy的方向,可以吗? - Asad Saeeduddin
@Asad 是的,不幸的是它并没有改变结果。 - SpaceFace
1个回答

6

我明白了!

我开始在纸上绘制数轴,并意识到问题出在我的坐标轴计算上。要计算垂直向量,您需要交换x和y坐标,然后再反转一个,我完全忘记了交换坐标。

新代码

var vx =    vertsay[ i ] - vertsay[ j ];
var vy = -( vertsax[ i ] - vertsax[ j ] );

如果您已经解决了您的问题,请将您的答案标记为“答案”! - A. Webb

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