aboutsummaryrefslogtreecommitdiff
path: root/src/libjin-lua/scripts/physics/physics.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin-lua/scripts/physics/physics.lua')
-rw-r--r--src/libjin-lua/scripts/physics/physics.lua260
1 files changed, 130 insertions, 130 deletions
diff --git a/src/libjin-lua/scripts/physics/physics.lua b/src/libjin-lua/scripts/physics/physics.lua
index 9b24a55..897af8d 100644
--- a/src/libjin-lua/scripts/physics/physics.lua
+++ b/src/libjin-lua/scripts/physics/physics.lua
@@ -69,22 +69,22 @@ local function rect_getSegmentIntersectionIndices(x,y,w,h, x1,y1,x2,y2, ti1,ti2)
if side == 1 then nx,ny,p,q = -1, 0, -dx, x1 - x -- left
elseif side == 2 then nx,ny,p,q = 1, 0, dx, x + w - x1 -- right
elseif side == 3 then nx,ny,p,q = 0, -1, -dy, y1 - y -- top
- else nx,ny,p,q = 0, 1, dy, y + h - y1 -- bottom
+ else nx,ny,p,q = 0, 1, dy, y + h - y1 -- bottom
end
if p == 0 then
- if q <= 0 then return nil end
+ if q <= 0 then return nil end
else
- r = q / p
- if p < 0 then
- if r > ti2 then return nil
- elseif r > ti1 then ti1,nx1,ny1 = r,nx,ny
- end
- else -- p > 0
- if r < ti1 then return nil
- elseif r < ti2 then ti2,nx2,ny2 = r,nx,ny
- end
- end
+ r = q / p
+ if p < 0 then
+ if r > ti2 then return nil
+ elseif r > ti1 then ti1,nx1,ny1 = r,nx,ny
+ end
+ else -- p > 0
+ if r < ti1 then return nil
+ elseif r < ti2 then ti2,nx2,ny2 = r,nx,ny
+ end
+ end
end
end
@@ -94,19 +94,19 @@ end
-- Calculates the minkowsky difference between 2 rects, which is another rect
local function rect_getDiff(x1,y1,w1,h1, x2,y2,w2,h2)
return x2 - x1 - w1,
- y2 - y1 - h1,
- w1 + w2,
- h1 + h2
+ y2 - y1 - h1,
+ w1 + w2,
+ h1 + h2
end
local function rect_containsPoint(x,y,w,h, px,py)
- return px - x > DELTA and py - y > DELTA and
- x + w - px > DELTA and y + h - py > DELTA
+ return px - x > DELTA and py - y > DELTA and
+ x + w - px > DELTA and y + h - py > DELTA
end
local function rect_isIntersecting(x1,y1,w1,h1, x2,y2,w2,h2)
return x1 < x2+w2 and x2 < x1+w1 and
- y1 < y2+h2 and y2 < y1+h1
+ y1 < y2+h2 and y2 < y1+h1
end
local function rect_getSquareDistance(x1,y1,w1,h1, x2,y2,w2,h2)
@@ -119,7 +119,7 @@ local function rect_detectCollision(x1,y1,w1,h1, x2,y2,w2,h2, goalX, goalY)
goalX = goalX or x1
goalY = goalY or y1
- local dx, dy = goalX - x1, goalY - y1
+ local dx, dy = goalX - x1, goalY - y1
local x,y,w,h = rect_getDiff(x1,y1,w1,h1, x2,y2,w2,h2)
local overlaps, ti, nx, ny
@@ -127,7 +127,7 @@ local function rect_detectCollision(x1,y1,w1,h1, x2,y2,w2,h2, goalX, goalY)
if rect_containsPoint(x,y,w,h, 0,0) then -- item was intersecting other
local px, py = rect_getNearestCorner(x,y,w,h, 0, 0)
local wi, hi = min(w1, abs(px)), min(h1, abs(py)) -- area of intersection
- ti = -wi * hi -- ti is the negative area of intersection
+ ti = -wi * hi -- ti is the negative area of intersection
overlaps = true
else
local ti1,ti2,nx1,ny1 = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, math.huge)
@@ -137,10 +137,10 @@ local function rect_detectCollision(x1,y1,w1,h1, x2,y2,w2,h2, goalX, goalY)
and ti1 < 1
and (abs(ti1 - ti2) >= DELTA) -- special case for rect going through another rect's corner
and (0 < ti1 + DELTA
- or 0 == ti1 and ti2 > 0)
+ or 0 == ti1 and ti2 > 0)
then
- ti, nx, ny = ti1, nx1, ny1
- overlaps = false
+ ti, nx, ny = ti1, nx1, ny1
+ overlaps = false
end
end
@@ -150,17 +150,17 @@ local function rect_detectCollision(x1,y1,w1,h1, x2,y2,w2,h2, goalX, goalY)
if overlaps then
if dx == 0 and dy == 0 then
- -- intersecting and not moving - use minimum displacement vector
- local px, py = rect_getNearestCorner(x,y,w,h, 0,0)
- if abs(px) < abs(py) then py = 0 else px = 0 end
- nx, ny = sign(px), sign(py)
- tx, ty = x1 + px, y1 + py
+ -- intersecting and not moving - use minimum displacement vector
+ local px, py = rect_getNearestCorner(x,y,w,h, 0,0)
+ if abs(px) < abs(py) then py = 0 else px = 0 end
+ nx, ny = sign(px), sign(py)
+ tx, ty = x1 + px, y1 + py
else
- -- intersecting and moving - move in the opposite direction
- local ti1, _
- ti1,_,nx,ny = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, 1)
- if not ti1 then return end
- tx, ty = x1 + dx * ti1, y1 + dy * ti1
+ -- intersecting and moving - move in the opposite direction
+ local ti1, _
+ ti1,_,nx,ny = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, 1)
+ if not ti1 then return end
+ tx, ty = x1 + dx * ti1, y1 + dy * ti1
end
else -- tunnel
tx, ty = x1 + dx * ti, y1 + dy * ti
@@ -168,8 +168,8 @@ local function rect_detectCollision(x1,y1,w1,h1, x2,y2,w2,h2, goalX, goalY)
return {
overlaps = overlaps,
- ti = ti,
- move = {x = dx, y = dy},
+ ti = ti,
+ move = {x = dx, y = dy},
normal = {x = nx, y = ny},
touch = {x = tx, y = ty},
itemRect = {x = x1, y = y1, w = w1, h = h1},
@@ -206,11 +206,11 @@ local function grid_traverse_initStep(cellSize, ct, t1, t2)
end
local function grid_traverse(cellSize, x1,y1,x2,y2, f)
- local cx1,cy1 = grid_toCell(cellSize, x1,y1)
- local cx2,cy2 = grid_toCell(cellSize, x2,y2)
+ local cx1,cy1 = grid_toCell(cellSize, x1,y1)
+ local cx2,cy2 = grid_toCell(cellSize, x2,y2)
local stepX, dx, tx = grid_traverse_initStep(cellSize, cx1, x1, x2)
local stepY, dy, ty = grid_traverse_initStep(cellSize, cy1, y1, y2)
- local cx,cy = cx1,cy1
+ local cx,cy = cx1,cy1
f(cx, cy)
@@ -219,13 +219,13 @@ local function grid_traverse(cellSize, x1,y1,x2,y2, f)
-- when we are *next* to the last cell
while abs(cx - cx2) + abs(cy - cy2) > 1 do
if tx < ty then
- tx, cx = tx + dx, cx + stepX
- f(cx, cy)
+ tx, cx = tx + dx, cx + stepX
+ f(cx, cy)
else
- -- Addition: include both cells when going through corners
- if tx == ty then f(cx + stepX, cy) end
- ty, cy = ty + dy, cy + stepY
- f(cx, cy)
+ -- Addition: include both cells when going through corners
+ if tx == ty then f(cx + stepX, cy) end
+ ty, cy = ty + dy, cy + stepY
+ f(cx, cy)
end
end
@@ -260,9 +260,9 @@ local slide = function(world, col, x,y,w,h, goalX, goalY, filter)
local tch, move = col.touch, col.move
if move.x ~= 0 or move.y ~= 0 then
if col.normal.x ~= 0 then
- goalX = tch.x
+ goalX = tch.x
else
- goalY = tch.y
+ goalY = tch.y
end
end
@@ -289,7 +289,7 @@ local bounce = function(world, col, x,y,w,h, goalX, goalY, filter)
end
col.bounce = {x = bx, y = by}
- x,y = tch.x, tch.y
+ x,y = tch.x, tch.y
goalX, goalY = bx, by
local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter)
@@ -347,14 +347,14 @@ local function getDictItemsInCellRect(self, cl,ct,cw,ch)
for cy=ct,ct+ch-1 do
local row = self.rows[cy]
if row then
- for cx=cl,cl+cw-1 do
- local cell = row[cx]
- if cell and cell.itemCount > 0 then -- no cell.itemCount > 1 because tunneling
- for item,_ in pairs(cell.items) do
- items_dict[item] = true
- end
- end
- end
+ for cx=cl,cl+cw-1 do
+ local cell = row[cx]
+ if cell and cell.itemCount > 0 then -- no cell.itemCount > 1 because tunneling
+ for item,_ in pairs(cell.items) do
+ items_dict[item] = true
+ end
+ end
+ end
end
end
@@ -386,21 +386,21 @@ local function getInfoAboutItemsTouchedBySegment(self, x1,y1, x2,y2, filter)
for i=1,len do
cell = cells[i]
for item in pairs(cell.items) do
- if not visited[item] then
- visited[item] = true
- if (not filter or filter(item)) then
- rect = self.rects[item]
- l,t,w,h = rect.x,rect.y,rect.w,rect.h
-
- ti1,ti2 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, 0, 1)
- if ti1 and ((0 < ti1 and ti1 < 1) or (0 < ti2 and ti2 < 1)) then
- -- the sorting is according to the t of an infinite line, not the segment
- tii0,tii1 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, -math.huge, math.huge)
- itemInfoLen = itemInfoLen + 1
- itemInfo[itemInfoLen] = {item = item, ti1 = ti1, ti2 = ti2, weight = min(tii0,tii1)}
- end
- end
- end
+ if not visited[item] then
+ visited[item] = true
+ if (not filter or filter(item)) then
+ rect = self.rects[item]
+ l,t,w,h = rect.x,rect.y,rect.w,rect.h
+
+ ti1,ti2 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, 0, 1)
+ if ti1 and ((0 < ti1 and ti1 < 1) or (0 < ti2 and ti2 < 1)) then
+ -- the sorting is according to the t of an infinite line, not the segment
+ tii0,tii1 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, -math.huge, math.huge)
+ itemInfoLen = itemInfoLen + 1
+ itemInfo[itemInfoLen] = {item = item, ti1 = ti1, ti2 = ti2, weight = min(tii0,tii1)}
+ end
+ end
+ end
end
end
table.sort(itemInfo, sortByWeight)
@@ -436,7 +436,7 @@ function World:project(item, x,y,w,h, goalX, goalY, filter)
-- This could probably be done with less cells using a polygon raster over the cells instead of a
-- bounding rect of the whole movement. Conditional to building a queryPolygon method
- local tl, tt = min(goalX, x), min(goalY, y)
+ local tl, tt = min(goalX, x), min(goalY, y)
local tr, tb = max(goalX + w, x+w), max(goalY + h, y+h)
local tw, th = tr-tl, tb-tt
@@ -446,22 +446,22 @@ function World:project(item, x,y,w,h, goalX, goalY, filter)
for other,_ in pairs(dictItemsInCellRect) do
if not visited[other] then
- visited[other] = true
+ visited[other] = true
- local responseName = filter(item, other)
- if responseName then
- local ox,oy,ow,oh = self:getRect(other)
- local col = rect_detectCollision(x,y,w,h, ox,oy,ow,oh, goalX, goalY)
+ local responseName = filter(item, other)
+ if responseName then
+ local ox,oy,ow,oh = self:getRect(other)
+ local col = rect_detectCollision(x,y,w,h, ox,oy,ow,oh, goalX, goalY)
- if col then
- col.other = other
- col.item = item
- col.type = responseName
+ if col then
+ col.other = other
+ col.item = item
+ col.type = responseName
- len = len + 1
- collisions[len] = col
- end
- end
+ len = len + 1
+ collisions[len] = col
+ end
+ end
end
end
@@ -474,7 +474,7 @@ function World:countCells()
local count = 0
for _,row in pairs(self.rows) do
for _,_ in pairs(row) do
- count = count + 1
+ count = count + 1
end
end
return count
@@ -533,8 +533,8 @@ function World:queryRect(x,y,w,h, filter)
if (not filter or filter(item))
and rect_isIntersecting(x,y,w,h, rect.x, rect.y, rect.w, rect.h)
then
- len = len + 1
- items[len] = item
+ len = len + 1
+ items[len] = item
end
end
@@ -553,8 +553,8 @@ function World:queryPoint(x,y, filter)
if (not filter or filter(item))
and rect_containsPoint(rect.x, rect.y, rect.w, rect.h, x, y)
then
- len = len + 1
- items[len] = item
+ len = len + 1
+ items[len] = item
end
end
@@ -572,7 +572,7 @@ end
function World:querySegmentWithCoords(x1, y1, x2, y2, filter)
local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, x2, y2, filter)
- local dx, dy = x2-x1, y2-y1
+ local dx, dy = x2-x1, y2-y1
local info, ti1, ti2
for i=1, len do
info = itemInfo[i]
@@ -580,10 +580,10 @@ function World:querySegmentWithCoords(x1, y1, x2, y2, filter)
ti2 = info.ti2
info.weight = nil
- info.x1 = x1 + dx * ti1
- info.y1 = y1 + dy * ti1
- info.x2 = x1 + dx * ti2
- info.y2 = y1 + dy * ti2
+ info.x1 = x1 + dx * ti1
+ info.y1 = y1 + dy * ti1
+ info.x2 = x1 + dx * ti2
+ info.y2 = y1 + dy * ti2
end
return itemInfo, len
end
@@ -603,7 +603,7 @@ function World:add(item, x,y,w,h)
local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h)
for cy = ct, ct+ch-1 do
for cx = cl, cl+cw-1 do
- addItemToCell(self, item, cx, cy)
+ addItemToCell(self, item, cx, cy)
end
end
@@ -617,7 +617,7 @@ function World:remove(item)
local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h)
for cy = ct, ct+ch-1 do
for cx = cl, cl+cw-1 do
- removeItemFromCell(self, item, cx, cy)
+ removeItemFromCell(self, item, cx, cy)
end
end
end
@@ -635,27 +635,27 @@ function World:update(item, x2,y2,w2,h2)
if cl1 ~= cl2 or ct1 ~= ct2 or cw1 ~= cw2 or ch1 ~= ch2 then
- local cr1, cb1 = cl1+cw1-1, ct1+ch1-1
- local cr2, cb2 = cl2+cw2-1, ct2+ch2-1
- local cyOut
+ local cr1, cb1 = cl1+cw1-1, ct1+ch1-1
+ local cr2, cb2 = cl2+cw2-1, ct2+ch2-1
+ local cyOut
- for cy = ct1, cb1 do
- cyOut = cy < ct2 or cy > cb2
- for cx = cl1, cr1 do
- if cyOut or cx < cl2 or cx > cr2 then
- removeItemFromCell(self, item, cx, cy)
- end
- end
- end
+ for cy = ct1, cb1 do
+ cyOut = cy < ct2 or cy > cb2
+ for cx = cl1, cr1 do
+ if cyOut or cx < cl2 or cx > cr2 then
+ removeItemFromCell(self, item, cx, cy)
+ end
+ end
+ end
- for cy = ct2, cb2 do
- cyOut = cy < ct1 or cy > cb1
- for cx = cl2, cr2 do
- if cyOut or cx < cl1 or cx > cr1 then
- addItemToCell(self, item, cx, cy)
- end
- end
- end
+ for cy = ct2, cb2 do
+ cyOut = cy < ct1 or cy > cb1
+ for cx = cl2, cr2 do
+ if cyOut or cx < cl1 or cx > cr1 then
+ addItemToCell(self, item, cx, cy)
+ end
+ end
+ end
end
@@ -690,7 +690,7 @@ function World:check(item, goalX, goalY, filter)
while projected_len > 0 do
local col = projected_cols[1]
- len = len + 1
+ len = len + 1
cols[len] = col
visited[col.other] = true
@@ -698,11 +698,11 @@ function World:check(item, goalX, goalY, filter)
local response = getResponseByName(self, col.type)
goalX, goalY, projected_cols, projected_len = response(
- self,
- col,
- x, y, w, h,
- goalX, goalY,
- visitedFilter
+ self,
+ col,
+ x, y, w, h,
+ goalX, goalY,
+ visitedFilter
)
end
@@ -716,9 +716,9 @@ bump.newWorld = function(cellSize)
cellSize = cellSize or 64
assertIsPositiveNumber(cellSize, 'cellSize')
local world = setmetatable({
- cellSize = cellSize,
- rects = {},
- rows = {},
+ cellSize = cellSize,
+ rects = {},
+ rows = {},
nonEmptyCells = {},
responses = {}
}, World_mt)
@@ -732,13 +732,13 @@ bump.newWorld = function(cellSize)
end
bump.rect = {
- getNearestCorner = rect_getNearestCorner,
+ getNearestCorner = rect_getNearestCorner,
getSegmentIntersectionIndices = rect_getSegmentIntersectionIndices,
- getDiff = rect_getDiff,
- containsPoint = rect_containsPoint,
- isIntersecting = rect_isIntersecting,
- getSquareDistance = rect_getSquareDistance,
- detectCollision = rect_detectCollision
+ getDiff = rect_getDiff,
+ containsPoint = rect_containsPoint,
+ isIntersecting = rect_isIntersecting,
+ getSquareDistance = rect_getSquareDistance,
+ detectCollision = rect_detectCollision
}
bump.responses = {