Hi, another way to deal with jumping is to check the distance between objects - which gives excellent results. A platformer demo featuring this should appear at the end of this week. I paste parts of the code in case you wish to use it nevertheless. Note that the exact polygon-polygon collision isn't added but I don't have time to fill that in right now, I'm afraid.
shapeDistance(shape1, shape2) returns distance, x1, y1, x2, y2, where (x1, y1) is the nearest point on shape1 and (x2, y2) is the nearest point on shape2. shapeDistanceQuick does the same but is much faster because it only checks the bounding box. It is advisable to first use the quick check and then the full if two shapes are actually nearby.
Code: Select all
function nearRelPointLineSegPoint(lx1, ly1, lx2, ly2, px, py)
local r = ((lx2 - lx1) * (px - lx1) + (ly2 - ly1) * (py - ly1)) / ((lx2-lx1)^2 + (ly2-ly1)^2)
return math.min(math.max(0,r),1)
end
function nearPointLineSegPoint(lx1, ly1, lx2, ly2, px, py)
local r = nearRelPointLineSegPoint(lx1, ly1, lx2, ly2, px, py)
return (1-r)*lx1 + r*lx2, (1-r)*ly1 + r*ly2
end
function distLineSegPoint(lx1, ly1, lx2, ly2, px, py)
local r = nearRelPointLineSegPoint(lx1, ly1, lx2, ly2, px, py)
local ret = (((1-r)*lx1 + r*lx2 - px)^2 + ((1-r)*ly1 + r*ly2 - py)^2)^0.5
return ret
end
function distLineSegLineSeg(lx1, ly1, lx2, ly2, lx3, ly3, lx4, ly4)
return math.min(
distLineSegPoint(lx1, ly1, lx2, ly2, lx3, ly3),
distLineSegPoint(lx1, ly1, lx2, ly2, lx4, ly4),
distLineSegPoint(lx3, ly3, lx4, ly4, lx1, ly1),
distLineSegPoint(lx3, ly3, lx4, ly4, lx2, ly2)
)
end
--~ function shapeDistanceQuick(shape1, shape2)
--~ local x1,y1,x2,y2,x3,y3,x4,y4 = shape1:getBoundingBox()
--~ local u1,v1,u2,v2,u3,v3,u4,v4 = shape2:getBoundingBox()
--~ return (math.max(0,u2 - x4, x2 - u4)^2
--~ + math.max(0,v2 - y4, y2 - v4)^2)^0.5
--~ end
function shapeDistanceQuick(shape1, shape2)
local x1,y1,x2,y2,x3,y3,x4,y4 = shape1:getBoundingBox()
local u1,v1,u2,v2,u3,v3,u4,v4 = shape2:getBoundingBox()
local bx, bu, by, bv
if u2 > x4 then
bx = x4; bu = u2
elseif x2 > u4 then
bx = x2; bu = u4
else
bx = math.min(u4, x4) / 2 + math.max(u2, x2) / 2; bu = bx
end
if v2 > y4 then
by = y4; bv = v2
elseif y2 > v4 then
by = y2; bv = v4
else
by = math.min(v4, y4) / 2 + math.max(v2, y2) / 2; bv = by
end
return ((bx-bu)^2+(by-bv)^2)^0.5, bx, by, bu, bv
end
-- Assumes circles are not offset. If so, please set offsetX and offsetY in data.
function shapeDistance(shape1, shape2)
if shape1 == shape2 then return nil end
if shape1:getType() == love.shape_circle then
if shape2:getType() == love.shape_circle then
local data1 = shape1:getData()
local data2 = shape2:getData()
local x1, y1 = data1.body:getData():getPosition()
if data1.offsetX then x1 = x1 + data1.offsetX; end
if data1.offsetY then y1 = y1 + data1.offsetY; end
local x2, y2 = data2.body:getPosition()
if data2.offsetX then x2 = x2 + data2.offsetX; end
if data2.offsetY then y2 = y2 + data2.offsetY; end
local dx = x2 - x1
local dy = y2 - y1
local d = (dx^2 + dy^2)^0.5
local r = shape1:getRadius() + shape2:getRadius()
if d > 0 then
x1 = x1 + shape1:getRadius() * dx / math.max(d,r)
y1 = y1 + shape1:getRadius() * dy / math.max(d,r)
x2 = x2 - shape2:getRadius() * dx / math.max(d,r)
y2 = y2 - shape2:getRadius() * dy / math.max(d,r)
end
return d-r, x1, y1, x2, y2, dx, dy
elseif shape2:getType() == love.shape_polygon then
local data1 = shape1:getData()
local x1, y1 = data1.body:getPosition()
if data1.offsetX then x1 = x1 + data1.offsetX; end
-- Warning: table creation tends to be slow
local points = {shape2:getPoints()}
local n = #points
local mindis = distLineSegPoint(points[n-1], points[n], points[1], points[2], x1, y1)
local mink = n/2
local dis
for k=1,n/2-1 do
dis = distLineSegPoint(points[2*k-1], points[2*k], points[2*k+1], points[2*k+2], x1, y1)
if dis < mindis then
mindis = dis
mink = k
end
end
local x2, y2 = nearPointLineSegPoint(points[2*mink-1], points[2*mink],
points[(2*mink)%n+1], points[(2*mink+1)%n+1], x1, y1)
local r = shape1:getRadius()
local dx = x2 - x1
local dy = y2 - y1
if mindis > 0 then
x1 = x1 + math.min(r, mindis) * dx / mindis
y1 = y1 + math.min(r, mindis) * dy / mindis
end
return math.max(mindis - r, 0), x1, y1, x2, y2, dx, dy
end
elseif shape1:getType() == love.shape_polygon then
if shape2:getType() == love.shape_circle then
local d, x1, y1, x2, y2 = shapeDistance(shape2, shape1)
return d, x2, y2, x1, y1
elseif shape2:getType() == love.shape_polygon then
end
end
end