From 5f1a51beac2742ad9096628dd3576f6418fae41c Mon Sep 17 00:00:00 2001 From: jill Date: Tue, 27 Oct 2020 17:28:10 +0300 Subject: [PATCH] object collision --- def.lua | 6 ++- main.lua | 74 +++----------------------- obj.lua | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 67 deletions(-) create mode 100644 obj.lua diff --git a/def.lua b/def.lua index e93b305..e8731cf 100644 --- a/def.lua +++ b/def.lua @@ -8,6 +8,7 @@ tiles = { count = 1, }, cost = 10, + collision = true, desc = 'An axe clicker. Used to obtain wood.', }, @@ -20,6 +21,7 @@ tiles = { count = 0.25, }, cost = 100, + collision = true, desc = 'A primitive chainsaw. Automatically collects wood.' }, @@ -29,7 +31,8 @@ tiles = { type = 'conveyor', cost = 5, speed = 1, - desc = 'Moves a resource from point a to point b' + desc = 'Moves a resource from point a to point b', + collision = false, }, { name = 'basic_seller', @@ -38,6 +41,7 @@ tiles = { cost = 1500, rate = 1, desc = 'A basic seller. Automatically sells all items coming from the forward tile', + collision = false, -- custom collision for sellers } } diff --git a/main.lua b/main.lua index cc29d81..9173b97 100644 --- a/main.lua +++ b/main.lua @@ -1,7 +1,9 @@ require 'util' require 'drawutil' require 'def' --- crusty swamp ass language An Awesome Project + +local obj = require 'obj' + width = 64 height = 64 @@ -14,7 +16,7 @@ sprites = {} money = 0 -local objects = {} +objects = {} local selectedTile = 1 local defaultTileRotation = 0 @@ -58,6 +60,8 @@ end local timer = 0 function love.update(dt) + --dt = dt * 0.1 + for x = 1, width do for y = 1, height do local tileid = getTile(x, y) @@ -86,69 +90,7 @@ function love.update(dt) timer = timer + dt for i,o in ipairs(objects) do - 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 pass = true - 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 - o.vely = o.vely - math.cos(math.rad(a)) * onTile.speed - 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 - else - pass = false - end - end - else - pass = false - end - end - - --[[ - for i2,o2 in ipairs(objects) do - if i ~= i2 and rectangleTouchingRectangle(o.x - o.size, o.y - o.size, o.size, o.size, o2.x - o2.size, o2.y - o2.size, o2.size, o2.size) then - pass = false - end - end - -- this doesnt work - ]] - - if not pass then - o.velx = -o.velx - o.vely = -o.vely - 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 - - o.x = o.x + o.velx * dt - o.y = o.y + o.vely * dt - o.velx = o.velx * 0.8 - o.vely = o.vely * 0.8 + obj.updateObject(i, o, dt) end end @@ -261,7 +203,7 @@ function love.mousepressed(x, y, button) if tileid[1] ~= 0 then local tile = tiles[tileid[1]] if tile.type == 'clicker' then - local a = -tileid.rotation * 90 + local a = -tileid.rotation * 90 + math.random(-10, 10)/10 local x = math.floor(x/tilesize) + 0.5 - math.sin(math.rad(a)) * 0.7 local y = math.floor(y/tilesize) + 0.5 - math.cos(math.rad(a)) * 0.7 diff --git a/obj.lua b/obj.lua new file mode 100644 index 0000000..b97636a --- /dev/null +++ b/obj.lua @@ -0,0 +1,154 @@ +-- 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 \ No newline at end of file