499 lines
No EOL
12 KiB
Lua
499 lines
No EOL
12 KiB
Lua
-- Collider v2.0
|
|
|
|
local collider = {}
|
|
|
|
collider.colliders = {}
|
|
collider.boxIDs = {}
|
|
collider.circleIDs = {}
|
|
|
|
function collider.newBox(x, y, width, height, tag, trigger, debugColor)
|
|
|
|
local newBox = {}
|
|
|
|
newBox.x = x
|
|
newBox.y = y
|
|
newBox.width = width
|
|
newBox.height = height or newBox.width
|
|
newBox.tag = tag or 'none'
|
|
if trigger == nil then
|
|
newBox.trigger = false
|
|
else
|
|
newBox.trigger = trigger
|
|
end
|
|
newBox.debugColor = debugColor or {1,1,1}
|
|
|
|
newBox.ID = tostring('B'..#collider.boxIDs+1)
|
|
newBox.onTriggerEnter = onTriggerEnter or function(collider) end
|
|
newBox.onTriggerExit = onTriggerExit or function(collider) end
|
|
newBox.collisions = {}
|
|
newBox.lastFrameCollisions = {}
|
|
|
|
newBox.type = 'box'
|
|
|
|
newBox.superPoints = {
|
|
{
|
|
x = newBox.x,
|
|
y = newBox.y
|
|
},
|
|
{
|
|
x = newBox.x + newBox.width,
|
|
y = newBox.y + newBox.height
|
|
},
|
|
|
|
updatePoint = function(point, x, y)
|
|
newBox.superPoints[point].x = x
|
|
newBox.superPoints[point].y = y
|
|
end
|
|
}
|
|
|
|
function newBox.updatePos(newX, newY, center)
|
|
if center == nil then
|
|
center = false
|
|
end
|
|
|
|
if center == true then
|
|
newBox.x = newX - newBox.width/2
|
|
newBox.y = newY - newBox.height/2
|
|
else
|
|
newBox.x = newX
|
|
newBox.y = newY
|
|
end
|
|
|
|
newBox.superPoints.updatePoint(1, newBox.x, newBox.y)
|
|
newBox.superPoints.updatePoint(2, newBox.x + newBox.width, newBox.y + newBox.height)
|
|
end
|
|
|
|
function newBox.collidingWith(id)
|
|
return newBox.collisions[id] ~= nil
|
|
end
|
|
|
|
function newBox.getID()
|
|
return newBox.ID
|
|
end
|
|
|
|
-- NOT WORKING
|
|
function newBox.destroy()
|
|
for k,v in ipairs(collider.boxIDs) do
|
|
if v == newBox.ID then
|
|
v = nil
|
|
end
|
|
end
|
|
collider.colliders[newBox.ID] = nil
|
|
end
|
|
|
|
collider.colliders[newBox.ID] = newBox
|
|
newBox.IDindex = #collider.boxIDs + 1
|
|
collider.boxIDs[newBox.IDindex] = newBox.ID
|
|
|
|
return newBox
|
|
|
|
end
|
|
|
|
function collider.newCircle(x, y, radius, tag, trigger, debugColor)
|
|
|
|
local newCircle = {}
|
|
|
|
newCircle.x = x
|
|
newCircle.y = y
|
|
newCircle.radius = radius or 50
|
|
newCircle.tag = tag or 'none'
|
|
if trigger == nil then
|
|
newCircle.trigger = false
|
|
else
|
|
newCircle.trigger = trigger
|
|
end
|
|
newCircle.debugColor = debugColor or {1,1,1}
|
|
|
|
newCircle.ID = tostring('C'..#collider.circleIDs+1)
|
|
newCircle.onTriggerEnter = onTriggerEnter or function(collider) end
|
|
newCircle.onTriggerExit = onTriggerExit or function(collider) end
|
|
newCircle.collisions = {}
|
|
newCircle.lastFrameCollisions = {}
|
|
|
|
newCircle.type = 'circle'
|
|
|
|
function newCircle.updatePos(newX, newY)
|
|
newCircle.x = newX
|
|
newCircle.y = newY
|
|
end
|
|
|
|
function newCircle.collidingWith(id)
|
|
return newCircle.collisions[id] ~= nil
|
|
end
|
|
|
|
function newCircle.getID()
|
|
return newCircle.ID
|
|
end
|
|
|
|
-- NOT WORKING
|
|
function newCircle.destroy()
|
|
for k,v in ipairs(collider.circleIDs) do
|
|
if v == newCircle.ID then
|
|
v = nil
|
|
end
|
|
end
|
|
collider.colliders[newCircle.ID] = nil
|
|
end
|
|
|
|
collider.colliders[newCircle.ID] = newCircle
|
|
newCircle.IDindex = #collider.circleIDs + 1
|
|
collider.circleIDs[newCircle.IDindex] = newCircle.ID
|
|
|
|
return newCircle
|
|
|
|
end
|
|
|
|
function collider.update()
|
|
collider.updateBoxes()
|
|
collider.updateCircles()
|
|
end
|
|
|
|
function collider.overlapBox(boxX, boxY, width, height)
|
|
|
|
local collisions = {}
|
|
|
|
local superPoints = {
|
|
{
|
|
x = boxX,
|
|
y = boxY
|
|
},
|
|
{
|
|
x = boxX + width,
|
|
y = boxY + height
|
|
},
|
|
}
|
|
|
|
-- Against every other box
|
|
for kk,other in ipairs(collider.boxIDs) do
|
|
other = collider.colliders[other]
|
|
|
|
-- Look for an x plane and y plane intersection in superPoints
|
|
local spX = {false, false}
|
|
local spY = {false, false}
|
|
|
|
-- Loop through superPoints
|
|
for kkk,sp in ipairs(superPoints) do
|
|
if sp.x > other.superPoints[1].x and sp.x < other.superPoints[2].x then
|
|
spY[kkk] = true
|
|
end
|
|
|
|
if sp.y > other.superPoints[1].y and sp.y < other.superPoints[2].y then
|
|
spX[kkk] = true
|
|
end
|
|
end
|
|
|
|
-- Check if superPoints show a collision between my and other
|
|
if (spX[1] and spY[1]) or (spX[2] and spY[2]) or (spX[1] and spY[2]) or (spX[2] and spY[1]) then
|
|
collisions[other.ID] = other
|
|
end
|
|
end
|
|
|
|
-- Against every other circle
|
|
for kk,other in ipairs(collider.circleIDs) do
|
|
other = collider.colliders[other]
|
|
|
|
local testX = other.x
|
|
local testY = other.y
|
|
|
|
if (other.x < boxX) then
|
|
testX = boxX -- left edge
|
|
elseif (other.x > boxX + width) then
|
|
testX = boxY + width -- right edge
|
|
end
|
|
|
|
if (other.y < boxY) then
|
|
testY = boxY -- top edge
|
|
elseif (other.y > boxY + height) then
|
|
testY = boxY + height -- bottom edge
|
|
end
|
|
|
|
local distX = other.x - testX;
|
|
local distY = other.y - testY;
|
|
local distance = (distX * distX) + (distY * distY);
|
|
|
|
if distance <= other.radius * other.radius then
|
|
collisions[other.ID] = other
|
|
end
|
|
end
|
|
|
|
return collisions
|
|
end
|
|
|
|
function collider.overlapCircle(x, y, radius)
|
|
|
|
local collisions = {}
|
|
|
|
-- Against every other box
|
|
for kk,other in ipairs(collider.boxIDs) do
|
|
other = collider.colliders[other]
|
|
|
|
local testX = x
|
|
local testY = y
|
|
|
|
if (x < other.x) then
|
|
testX = other.x -- left edge
|
|
elseif (x > other.x + other.width) then
|
|
testX = other.x + other.width -- right edge
|
|
end
|
|
|
|
if (y < other.y) then
|
|
testY = other.y -- top edge
|
|
elseif (y > other.y + other.height) then
|
|
testY = other.y + other.height -- bottom edge
|
|
end
|
|
|
|
local distX = x - testX;
|
|
local distY = y - testY;
|
|
local distance = (distX * distX) + (distY * distY);
|
|
|
|
if distance <= radius * radius then
|
|
collisions[other.ID] = other
|
|
end
|
|
end
|
|
|
|
-- Against every other circle
|
|
for kk,other in ipairs(collider.circleIDs) do
|
|
other = collider.colliders[other]
|
|
|
|
local distX = x - other.x;
|
|
local distY = y - other.y;
|
|
local distance = (distX*distX) + (distY*distY);
|
|
|
|
if (distance <= (radius+other.radius) * (radius+other.radius)) then
|
|
collisions[other.ID] = other
|
|
end
|
|
end
|
|
|
|
return collisions
|
|
end
|
|
|
|
function collider.updateBoxes()
|
|
|
|
for k,v in ipairs(collider.boxIDs) do
|
|
v = collider.colliders[v]
|
|
|
|
for kk in pairs (v.collisions) do
|
|
v.collisions[kk] = nil
|
|
end
|
|
end
|
|
|
|
-- Check every box for any collisions
|
|
for k,my in ipairs(collider.boxIDs) do
|
|
my = collider.colliders[my]
|
|
|
|
-- Against every other box
|
|
for kk,other in ipairs(collider.boxIDs) do
|
|
other = collider.colliders[other]
|
|
|
|
-- Ignore if it is yourself
|
|
if kk ~= k then
|
|
|
|
-- Look for an x plane and y plane intersection in superPoints
|
|
local spX = {false, false}
|
|
local spY = {false, false}
|
|
|
|
-- Loop through superPoints
|
|
for kkk,sp in ipairs(my.superPoints) do
|
|
if sp.x > other.superPoints[1].x and sp.x < other.superPoints[2].x then
|
|
spY[kkk] = true
|
|
end
|
|
|
|
if sp.y > other.superPoints[1].y and sp.y < other.superPoints[2].y then
|
|
spX[kkk] = true
|
|
end
|
|
end
|
|
|
|
-- Check if superPoints show a collision between my and other
|
|
if (spX[1] and spY[1]) or (spX[2] and spY[2]) or (spX[1] and spY[2]) or (spX[2] and spY[1]) then
|
|
if not my.collisions[other.ID] ~= nil or not other.collisions[my.ID] ~= nil then
|
|
my.collisions[other.ID] = other
|
|
other.collisions[my.ID] = my
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Against every other circle
|
|
for kk,other in ipairs(collider.circleIDs) do
|
|
other = collider.colliders[other]
|
|
|
|
local testX = other.x
|
|
local testY = other.y
|
|
|
|
if (other.x < my.x) then
|
|
testX = my.x -- left edge
|
|
elseif (other.x > my.x + my.width) then
|
|
testX = my.x + my.width -- right edge
|
|
end
|
|
|
|
if (other.y < my.y) then
|
|
testY = my.y -- top edge
|
|
elseif (other.y > my.y + my.height) then
|
|
testY = my.y + my.height -- bottom edge
|
|
end
|
|
|
|
local distX = other.x - testX;
|
|
local distY = other.y - testY;
|
|
local distance = (distX * distX) + (distY * distY);
|
|
|
|
if distance <= other.radius * other.radius then
|
|
my.collisions[other.ID] = other
|
|
other.collisions[my.ID] = my
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Update collision status
|
|
for k,my in ipairs(collider.boxIDs) do
|
|
my = collider.colliders[my]
|
|
|
|
for kk,other in pairs(my.collisions) do
|
|
|
|
-- Check if its a new collision
|
|
if my.lastFrameCollisions[other.ID] == nil then
|
|
|
|
my.lastFrameCollisions[other.ID] = other
|
|
|
|
my.onTriggerEnter(collider.colliders[other.ID])
|
|
collider.colliders[other.ID].lastFrameCollisions[my.ID] = my
|
|
collider.colliders[other.ID].onTriggerEnter(my)
|
|
end
|
|
end
|
|
|
|
for kk,other in pairs(my.lastFrameCollisions) do
|
|
|
|
-- Check if collisions from last frame aren't there anymore
|
|
if my.collisions[other.ID] == nil then
|
|
|
|
my.lastFrameCollisions[other.ID] = nil
|
|
|
|
my.onTriggerExit(collider.colliders[other.ID])
|
|
collider.colliders[other.ID].lastFrameCollisions[my.ID] = nil
|
|
collider.colliders[other.ID].onTriggerExit(my)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function collider.updateCircles()
|
|
|
|
for k,v in ipairs(collider.circleIDs) do
|
|
v = collider.colliders[v]
|
|
|
|
for kk in pairs (v.collisions) do
|
|
v.collisions[kk] = nil
|
|
end
|
|
end
|
|
|
|
-- Check every circle
|
|
for k,my in ipairs(collider.circleIDs) do
|
|
my = collider.colliders[my]
|
|
|
|
-- Against every other box
|
|
for kk,other in ipairs(collider.boxIDs) do
|
|
other = collider.colliders[other]
|
|
|
|
local testX = my.x
|
|
local testY = my.y
|
|
|
|
if (my.x < other.x) then
|
|
testX = other.x -- left edge
|
|
elseif (my.x > other.x + other.width) then
|
|
testX = other.x + other.width -- right edge
|
|
end
|
|
|
|
if (my.y < other.y) then
|
|
testY = other.y -- top edge
|
|
elseif (my.y > other.y + other.height) then
|
|
testY = other.y + other.height -- bottom edge
|
|
end
|
|
|
|
local distX = my.x - testX;
|
|
local distY = my.y - testY;
|
|
local distance = (distX * distX) + (distY * distY);
|
|
|
|
if distance <= my.radius * my.radius then
|
|
my.collisions[other.ID] = other
|
|
other.collisions[my.ID] = my
|
|
end
|
|
end
|
|
|
|
-- Against every other circle
|
|
for kk,other in ipairs(collider.circleIDs) do
|
|
if k ~= kk then
|
|
other = collider.colliders[other]
|
|
|
|
local distX = my.x - other.x;
|
|
local distY = my.y - other.y;
|
|
local distance = (distX*distX) + (distY*distY);
|
|
|
|
if (distance <= (my.radius+other.radius) * (my.radius+other.radius)) then
|
|
my.collisions[other.ID] = other
|
|
other.collisions[my.ID] = my
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Update collision status
|
|
for k,my in ipairs(collider.circleIDs) do
|
|
my = collider.colliders[my]
|
|
|
|
for kk,other in pairs(my.collisions) do
|
|
|
|
-- Check if its a new collision
|
|
if my.lastFrameCollisions[other.ID] == nil then
|
|
|
|
my.lastFrameCollisions[other.ID] = other
|
|
|
|
my.onTriggerEnter(collider.colliders[other.ID])
|
|
collider.colliders[other.ID].lastFrameCollisions[my.ID] = my
|
|
collider.colliders[other.ID].onTriggerEnter(my)
|
|
end
|
|
end
|
|
|
|
for kk,other in pairs(my.lastFrameCollisions) do
|
|
|
|
-- Check if collisions from last frame aren't there anymore
|
|
if my.collisions[other.ID] == nil then
|
|
|
|
my.lastFrameCollisions[other.ID] = nil
|
|
|
|
my.onTriggerExit(collider.colliders[other.ID])
|
|
collider.colliders[other.ID].lastFrameCollisions[my.ID] = nil
|
|
collider.colliders[other.ID].onTriggerExit(my)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function collider.draw()
|
|
for k,id in ipairs(collider.boxIDs) do
|
|
local v = collider.colliders[id]
|
|
|
|
if v ~= nil then
|
|
love.graphics.setColor(v.debugColor)
|
|
love.graphics.rectangle('line', v.x, v.y, v.width, v.height)
|
|
love.graphics.circle('fill', v.x + v.width/2, v.y + v.height/2, 3)
|
|
for kk,vv in ipairs(v.superPoints) do
|
|
love.graphics.circle('fill', vv.x, vv.y, 3)
|
|
end
|
|
love.graphics.print(v.ID, v.x + 5, v.y - 15)
|
|
love.graphics.print(v.tag, v.x + 5, v.y)
|
|
end
|
|
end
|
|
|
|
for k,id in ipairs(collider.circleIDs) do
|
|
local v = collider.colliders[id]
|
|
|
|
if v ~= nil then
|
|
love.graphics.setColor(v.debugColor)
|
|
love.graphics.circle('line', v.x, v.y, v.radius)
|
|
love.graphics.circle('fill', v.x, v.y, 3)
|
|
love.graphics.print(v.ID, v.x + 5, v.y - 15)
|
|
love.graphics.print(v.tag, v.x + 5, v.y)
|
|
end
|
|
end
|
|
end
|
|
|
|
return collider |