For context, variables like math.abs, math.sign(which is custom) and math.huge are cached above to abs, sign and huge.
Code: Select all
--set up the local variables
local totalxov, totalyov, minxov, minyov, minxov_ent, minyov_ent
--A function to setup the total overlap, minimum overlap and getting the relevant entity
local function collide_with_ent(ent)
if ent.solid ~= "full" then return end
local ox, oy = ent.x, ent.y
local ow, oh = ent.width, ent.height
local ohw, ohh = ow/2, oh/2
local myx, myy = self.x, self.y
local myw, myh = self.width, self.height
local myhw, myhh = myw/2, myh/2
local oleft, oright, otop, obottom = ox-ohw, ox+ohw, oy+ohh, oy-ohh
local myleft, myright, mytop, mybottom = myx-myhw, myx+myhw, myy+myhh, myy-myhh
if myx>ox then
local xov = myleft-oright
if abs(xov) < abs(minxov or huge) then
minxov_ent = ent
minxov = xov
end
totalxov = totalxov + abs(xov)
else
local xov = myright-oleft
if abs(xov) < abs(minxov or huge) then
minxov_ent = ent
minxov = xov
end
totalxov = totalxov + abs(xov)
end
if myy<oy then
local yov = mytop-obottom
if abs(yov) < abs(minyov or huge) then
minyov_ent = ent
minyov = yov
end
totalyov = totalyov + abs(yov)
else
local yov = mybottom-otop
if abs(yov) < abs(minyov or huge) then
minyov_ent = ent
minyov = yov
end
totalyov = totalyov + abs(yov)
end
end
local fix, tile
--Move on the X axis
self.x = self.x + vx
--Reset wall detection
self.wall = 0
--Collide with tiles on the X axis (Tiles work perfectly, it's just entities)
fix, tile = self:is_touching_solid("x")
--When we have a collision, collide
if fix ~= 0 then
self.x = self.x + fix * 1.01
if sign(vx) == -sign(fix) then
vx = 0
self.wall = sign(fix)
end
end
--Now my biggest enemy: entity collisions, the reason this is hard, is because I don't know the order:
--there are solid physics-based entities like munchers,
--so we can't seperate the solid and physics entities.
--I am currently testing the physics in the player, which always runs after the entities.
--So I think it works, but then I implement the engine into the entities, and it all breaks :(
--Reset the total overlap
totalxov, totalyov = 0, 0
--Reset the minimum overlap
minxov, minyov = nil, nil
--Handle entity collisions
for _, ent in ipairs(ENTITIES) do
if ent:colliding_with(self) then collide_with_ent(ent) end
end
--When we collided
if minxov then
--Move out
self.x = self.x - minxov
--When we actually collided on the X axis, reset vx
if totalxov < totalyov then
vx = 0
self.wall = -sign(minxov)
end
end
--Do the same on the Y axis
self.y = self.y + vy
airtime = airtime + 1
fix, tile = self:is_touching_solid("y")
if fix ~= 0 then
self.y = self.y + fix * 1.01
if sign(vy) == -sign(fix) then
if fix > 0 then
if airtime > 1 then
squish = -vy * 0.04
end
flip = 0
airtime = 0
end
if fix < 0 then
if tile then tile:hit(1) end
squish = 0.4
end
vy = 0
end
end
totalxov, totalyov = 0, 0
minxov, minyov = nil, nil
for _, ent in ipairs(ENTITIES) do
if ent:colliding_with(self) then collide_with_ent(ent) end
end
if minyov then
self.y = self.y - minyov
if totalyov < totalxov then
if minyov < 0 then
if airtime > 1 then
squish = -vy * 0.04
end
flip = 0
airtime = 0
self.x, self.y = self.x + minyov_ent.vx, self.y + minyov_ent.vy
end
if minyov > 0 then
squish = 0.4
end
vy = 0
end
end