Separating Axis Theorem function fails when met with acute angles

时间:2017-12-18 06:32:42

标签: lua collision love2d separating-axis-theorem

This is a little library I was making for the LOVE2D engine in Lua, which uses separating axis theorem to solve collisions.

I was so happy when I got my SAT program to work, and started testing it with a multitude of polygons. It works in most cases, and gives a correct minimum translation vector for them too. Oddly enough- if both shapes have acute angles, then those angles cause the program to fail, returning collisions when the shape isn't touching, or even more unusually, it gives a bizarre minimum translation vector. I have checked my function that returns normals- as I felt that this was my first point that could have failed, but it seems to be working fine.

This is the main function that handles my collision.

function findIntersection(shape1, shape2)
--Get axes to test.
--MTV means 'minimum translation vector' ie. the shortest vector of intersection
local axes1 = {}
local axes2 = {}
local overlap = false
local MTV = {direction = 0, magnitude = 99999}

for i, vert in pairs(shape1.hitbox) do
    nrm = getNormal(shape1.hitbox, i)
    table.insert(axes1, nrm)
end
for i, vert in pairs(shape2.hitbox)do
    nrm = getNormal(shape2.hitbox, i)
    table.insert(axes2, nrm)
end

--print(#axes1 .. '    ' .. #axes2)

--now that we have the axes, we have to project along each of them
for i, axis in pairs(axes1) do
    test1 = hitboxProj(shape1, vectorToCoord(axis.direction, axis.magnitude))
    test2 = hitboxProj(shape2, vectorToCoord(axis.direction, axis.magnitude))
    if test2.max > test1.min or test1.max > test2.min then
        if test2.max - test1.min < MTV.magnitude then
            MTV.direction = axes1[i].direction
            MTV.magnitude = test2.max - test1.min
        end
    else
        return false
    end
end

--now that we have the axes, we have to project along each of them
for i, axis in pairs(axes2) do
    test1 = hitboxProj(shape1, vectorToCoord(axis.direction, axis.magnitude))
    test2 = hitboxProj(shape2, vectorToCoord(axis.direction, axis.magnitude))
    if test2.max > test1.min or test1.max > test2.min then
        if test2.max - test1.min < MTV.magnitude then
            MTV.direction = axes2[i].direction
            MTV.magnitude = test2.max - test1.min
        end
    else
        return false
    end
end

return {MTV}
end

My project files are here on github https://github.com/ToffeeGoat/ToffeeCollision

1 个答案:

答案 0 :(得分:0)

这是一个好的开始,您的代码相当清晰。有一些可以改进的地方,特别是我看到您的所有功能都是全局的。对于初学者,您希望将所有功能存储在“模块”中,以避免污染_G空间。您可以将本地人用于其他所有事情。 请注意,编写x == 0之类的代码并不可靠,此检查仅适用于整数,并且在涉及浮点数学运算时可能会失败。我建议为库中的每个函数编写一个简单的测试脚本。

此外,当您可以使用Lua return {x = xCoord, y = yCoord}返回多个值时,编写return xCoord, yCoord效率不高。创建很多中间表给垃圾收集器带来了压力。 您的某些代码需要重新制作,例如“ getDirection”功能。我的意思是已经有用于此类事情的众所周知的技术。查看我的教程中的示例:https://2dengine.com/?p=vectors#Angle_between_two_vectors

其中有些愚蠢的东西,例如function sq(x) return x*x end。您知道您可以在Lua中写x ^ 2吗? addDeg可以由模运算符代替:newAng =(角度+加法)%360 另请注意,使用度数绝对没有好处-我建议仅使用弧度。您已经在使用以弧度表示的math.pi。无论哪种方式,您都必须选择弧度或度数并坚持一个或另一个。不要在代码中同时使用这两个单位。

我不想太挑剔,因为您的代码还不错,您只需要习惯一些最佳实践即可。这是我的另一本教程: https://2dengine.com/?p=intersections