factorite/obj.lua

154 lines
4.2 KiB
Lua

-- handles object collision and updates
require 'util'
local self = {}
local steps = 4 -- the more, the higher quality the collision is, however it becomes laggier
local clipAttempts = 10000
function self.doCollision(i, o, dt)
-- check if object is already colliding and try to clip it out
-- object collision
for i2,o2 in ipairs(objects) do
local touch = rectangleTouchingRectangle(o.x, o.y, o.size, o.size, o2.x, o2.y, o2.size, o2.size) and i ~= i2
if touch then
-- clip it out, m64 style
for i = 0, clipAttempts do
if not rectangleTouchingRectangle(o.x, o.y, o.size, o.size, o2.x, o2.y, o2.size, o2.size) then break end
local diffX = (o.x - o2.x) or o.size / 10 -- `or` incase the objects are spawned inside eachother
local diffY = (o.y - o2.y) or o.size / 10
o.x = diffX * 1.1 + o2.x
o.y = diffY * 1.1 + o2.y
end
end
end
-- tile collision
for i = 0, clipAttempts do
local pass = true
local onTileId = getTile(math.floor(o.x), math.floor(o.y))
if onTileId[1] ~= 0 then
local onTile = tiles[onTileId[1]]
local a = -(onTileId.rotation or 0) * 90
if onTile.collision then
if onTile.type == 'seller' then
local movementAngle = math.deg(math.atan2(o.vely, o.velx)) - 90
if onTileId.rotation then
local sellerAngle = onTileId.rotation * 90
if not math.abs(movementAngle - sellerAngle) < 45 then
pass = false
end
end
else
pass = false
end
end
end
if pass then break end
local diffX = (o.x % 1 - 0.5) or o.size / 10 -- `or` incase the objects are spawned inside eachother
local diffY = (o.y % 1 - 0.5) or o.size / 10
o.x = diffX * 1.1 + math.floor(o.x) + 0.5
o.y = diffY * 1.1 + math.floor(o.y) + 0.5
end
-- move
for step = 1, steps do
local a = step/steps
local x = o.x + o.velx * dt * a
local y = o.y + o.vely * dt * a
local pass = true
-- tile collision
local onTileId = getTile(math.floor(x), math.floor(y))
if onTileId[1] ~= 0 then
local onTile = tiles[onTileId[1]]
local a = -(onTileId.rotation or 0) * 90
if onTile.collision then
if onTile.type == 'seller' then
local movementAngle = math.deg(math.atan2(o.vely, o.velx)) - 90
if onTileId.rotation then
local sellerAngle = onTileId.rotation * 90
if not math.abs(movementAngle - sellerAngle) < 45 then
pass = false
end
end
else
pass = false
end
end
end
-- object collision
for i2,o2 in ipairs(objects) do
local touch = rectangleTouchingRectangle(o.x, o.y, o.size, o.size, o2.x, o2.y, o2.size, o2.size) and i ~= i2
if touch then pass = false end
end
if pass then
o.x = x
o.y = y
else
o.velx = -o.velx * 0.25
o.vely = -o.vely * 0.25
break
end
end
end
function self.updateObject(i, o, dt)
o.x = o.x or 0
o.y = o.y or 0
o.velx = o.velx or 0
o.vely = o.vely or 0
o.size = o.size or 0.5
o.color = o.color or {1, 1, 1}
o.despawntimer = o.despawntimer or 0
local object = objectTypes[o.type]
local onTileId = getTile(math.floor(o.x), math.floor(o.y))
if onTileId[1] ~= 0 then
local onTile = tiles[onTileId[1]]
local a = -(onTileId.rotation or 0) * 90
if onTile.type == 'conveyor' then
o.velx = o.velx - math.sin(math.rad(a)) * onTile.speed * dt * 40
o.vely = o.vely - math.cos(math.rad(a)) * onTile.speed * dt * 40
elseif onTile.type == 'seller' then
local movementAngle = math.deg(math.atan2(o.vely, o.velx)) - 90
if onTileId.rotation then
local sellerAngle = onTileId.rotation * 90
if math.abs(movementAngle - sellerAngle) < 45 then
table.remove(objects, i)
money = money + object.cost
end
end
end
end
if math.abs(o.velx) < 0.01 and math.abs(o.vely) < 0.01 then
o.despawntimer = o.despawntimer + dt
else
o.despawntimer = 0
end
if o.despawntimer > 5 then
table.remove(objects, i)
end
self.doCollision(i, o, dt)
o.velx = o.velx * 0.8
o.vely = o.vely * 0.8
end
return self