-- 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