After having made several more or less successful attempts to solve the problem of collision between any polygons, whether between convex, non-convex or even complex polygons, I would like to know your opinion on the subject and how you would approach this problem.
I have already developed a collision detection function between convex polygons, which returns a direction vector with the penetration distance, based on the SAT algorithm in my polyMan module. If you have any comments to make on this subject, I am also a taker.
Code: Select all
local function polyInPolyConvex(polygon1, polygon2, approximate)
local min_distance = huge
local min_nx, min_ny
local polygon = polygon1
local reiterated
::reiterated::
for i = 1, #polygon, 2 do
-- Calculate the normals for each line of both polygons
local x1, y1, x2, y2
if i == #polygon - 1 then
x1, y1 = polygon[i], polygon[i+1]
x2, y2 = polygon[1], polygon[2]
else
x1, y1 = polygon[i], polygon[i+1]
x2, y2 = polygon[i+2], polygon[i+3]
end
local nx, ny = y2-y1, x1-x2
local length = sqrt(nx * nx + ny * ny)
nx = nx / length
ny = ny / length
-- Checks the minimum distance between the two polygons along each normal
local min1, max1, min2, max2 = huge, -huge, huge, -huge
for j = 1, #polygon1, 2 do
local dot = nx * polygon1[j] + ny * polygon1[j+1]
min1 = min(min1, dot)
max1 = max(max1, dot)
end
for j = 1, #polygon2, 2 do
local dot = nx * polygon2[j] + ny * polygon2[j+1]
min2 = min(min2, dot)
max2 = max(max2, dot)
end
-- If the polygons do not overlap, there is no collision
if min1 > max2 or min2 > max1 then
return false
end
-- Get the penetration distance and keep the results if it is the current smallest
local distance = min(max2 - min1, max1 - min2)
if distance < min_distance then
min_distance = distance
min_nx, min_ny = nx, ny
if max2 - min1 > max1 - min2 then
min_nx = -min_nx
min_ny = -min_ny
end
end
end
if not approximate and not reiterated then
polygon, reiterated = polygon2, true
goto reiterated
end
return true, min_nx, min_ny, min_distance
end
Code: Select all
local function polyInPolyComplex(polygon1, polygon2)
local displacement_x, displacement_y = 0, 0
local num_collisions = 0
-- Triangulate polygons (using love.math.triangulate)
local triangles1 = love.math.triangulate(polygon1)
local triangles2 = love.math.triangulate(polygon2)
-- Check each triangle for collision using polyInPolyConvex (SAT) function
for i, tri1 in ipairs(triangles1) do
for j, tri2 in ipairs(triangles2) do
local collides, nx, ny, dist = polyInPolyConvex(tri1, tri2)
if collides then
-- Calculate displacement needed to separate polygons
local displacement = dist / math.sqrt(nx * nx + ny * ny)
local dx, dy = nx * displacement, ny * displacement
-- Accumulate displacement
displacement_x = displacement_x + dx
displacement_y = displacement_y + dy
num_collisions = num_collisions + 1
end
end
end
if num_collisions > 0 then
-- Calculate average displacement
displacement_x = displacement_x / num_collisions
displacement_y = displacement_y / num_collisions
return true, displacement_x, displacement_y
else
return false, 0, 0
end
end
Replace only the first polygon with this same function:
Do you have any suggestions to tackle this problem or even the solution let's be crazy because I already am a little crazy
If I forgot any details that you think are important, sorry in advance, but above all, don't hesitate.
I share with you the demo which is in gif, the `polyInPolyComplex` function is directly used there to replace the first polygon in parameter as it should do.