feat(fov): add recursive shadowcasting field of view
This commit is contained in:
1 parent
e296426703
commit
95684a7d76
1 file changed
+62
+62
@@ -0,0 +1,62 @@
|
|||||||
|
-- Recursive shadowcasting over eight octants. Returns a set of visible map
|
||||||
|
-- indices for a given origin and radius.
|
||||||
|
|
||||||
|
local Fov = {}
|
||||||
|
|
||||||
|
local mult = {
|
||||||
|
{ 1, 0, 0, -1, -1, 0, 0, 1 },
|
||||||
|
{ 0, 1, -1, 0, 0, -1, 1, 0 },
|
||||||
|
{ 0, 1, 1, 0, 0, -1, -1, 0 },
|
||||||
|
{ 1, 0, 0, 1, -1, 0, 0, -1 },
|
||||||
|
}
|
||||||
|
|
||||||
|
local function castLight(map, cx, cy, row, start, finish, radius, xx, xy, yx, yy, visible)
|
||||||
|
if start < finish then return end
|
||||||
|
local radiusSq = radius * radius
|
||||||
|
local newStart = 0.0
|
||||||
|
for j = row, radius do
|
||||||
|
local dx, dy = -j - 1, -j
|
||||||
|
local blocked = false
|
||||||
|
while dx <= 0 do
|
||||||
|
dx = dx + 1
|
||||||
|
local mapX = cx + dx * xx + dy * xy
|
||||||
|
local mapY = cy + dx * yx + dy * yy
|
||||||
|
local leftSlope = (dx - 0.5) / (dy + 0.5)
|
||||||
|
local rightSlope = (dx + 0.5) / (dy - 0.5)
|
||||||
|
if start < rightSlope then
|
||||||
|
-- cell not yet inside the current view; keep scanning
|
||||||
|
elseif finish > leftSlope then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
if dx * dx + dy * dy <= radiusSq and map:inBounds(mapX, mapY) then
|
||||||
|
visible[map:index(mapX, mapY)] = true
|
||||||
|
end
|
||||||
|
if blocked then
|
||||||
|
if map:blocksSight(mapX, mapY) then
|
||||||
|
newStart = rightSlope
|
||||||
|
else
|
||||||
|
blocked = false
|
||||||
|
start = newStart
|
||||||
|
end
|
||||||
|
elseif map:blocksSight(mapX, mapY) and j < radius then
|
||||||
|
blocked = true
|
||||||
|
castLight(map, cx, cy, j + 1, start, leftSlope, radius, xx, xy, yx, yy, visible)
|
||||||
|
newStart = rightSlope
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if blocked then break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Fov.compute(map, originX, originY, radius)
|
||||||
|
local visible = {}
|
||||||
|
visible[map:index(originX, originY)] = true
|
||||||
|
for octant = 1, 8 do
|
||||||
|
castLight(map, originX, originY, 1, 1.0, 0.0, radius,
|
||||||
|
mult[1][octant], mult[2][octant], mult[3][octant], mult[4][octant], visible)
|
||||||
|
end
|
||||||
|
return visible
|
||||||
|
end
|
||||||
|
|
||||||
|
return Fov
|
||||||
Reference in new issue
Block a user