111 lines
2.8 KiB
Lua
111 lines
2.8 KiB
Lua
function constrain(val, low, high)
|
|
if val > high then
|
|
return high
|
|
elseif val < low then
|
|
return low
|
|
else
|
|
return val
|
|
end
|
|
end
|
|
|
|
function map(value, inMin, inMax, outMin, outMax)
|
|
local inPercent = value / (inMax - inMin)
|
|
return (outMax - outMin) * (inPercent) + outMin
|
|
end
|
|
|
|
function lerp(a, b, amount)
|
|
return (1 - amount) * a + (amount * b)
|
|
end
|
|
|
|
-- Write to the project tree itself (not LÖVE's save dir) so edits persist in the
|
|
-- repo during dev. Uses plain io.open against love.filesystem.getSource(), which
|
|
-- is the absolute project path when running `love .` from a folder. Falls back to
|
|
-- love.filesystem.write (save dir) if the source is a packaged .love archive.
|
|
function writeToSource(relPath, contents)
|
|
local base = love.filesystem.getSource()
|
|
local file = io.open(base .. "/" .. relPath, "w")
|
|
if file then
|
|
file:write(contents)
|
|
file:close()
|
|
return true
|
|
end
|
|
return love.filesystem.write(relPath, contents)
|
|
end
|
|
|
|
-- Read from the project tree directly so a stale copy in LÖVE's save directory
|
|
-- can't shadow the real source file. Falls back to love.filesystem for a
|
|
-- packaged .love.
|
|
function readFromSource(relPath)
|
|
local base = love.filesystem.getSource()
|
|
local file = io.open(base .. "/" .. relPath, "r")
|
|
if file then
|
|
local contents = file:read("*a")
|
|
file:close()
|
|
return contents
|
|
end
|
|
return love.filesystem.read(relPath)
|
|
end
|
|
|
|
-- Cached image loader. The filesystem is the source of truth for art, so every
|
|
-- sprite is loaded on demand by path (deduped here) rather than from a
|
|
-- hand-maintained central table.
|
|
local spriteCache = {}
|
|
function loadSprite(path)
|
|
if not spriteCache[path] then
|
|
spriteCache[path] = love.graphics.newImage(path)
|
|
end
|
|
return spriteCache[path]
|
|
end
|
|
|
|
function cellShapeFromBox(box)
|
|
local cells = {}
|
|
for i = 1, box.w do
|
|
for j = 1, box.h do
|
|
table.insert(cells, {x = i, y = j})
|
|
end
|
|
end
|
|
return cells
|
|
end
|
|
|
|
-- Which 16x16 cells of a sprite are non-empty, for multi-cell collision shapes.
|
|
function getCellsFromSprite(sprite)
|
|
local w, h = sprite:getWidth(), sprite:getHeight()
|
|
local box = {w = w / 16, h = h / 16}
|
|
local boxCells = cellShapeFromBox(box)
|
|
if box.w < 1 or box.h < 1 then
|
|
return boxCells
|
|
end
|
|
|
|
local img = sprite:getData()
|
|
local cellsToRemove = {}
|
|
|
|
for _, cell in pairs(boxCells) do
|
|
local startPixel = {x = (cell.x - 1) * 16, y = (cell.y - 1) * 16}
|
|
local endPixel = {x = (cell.x * 16) - 1, y = (cell.y * 16) - 1}
|
|
local empty = true
|
|
|
|
for i = startPixel.x, endPixel.x do
|
|
for j = startPixel.y, endPixel.y do
|
|
local r, g, b, a = img:getPixel(i, j)
|
|
if a > 0 and (r > 0 or g > 0 or b > 0) then
|
|
empty = false
|
|
end
|
|
end
|
|
end
|
|
|
|
if empty then
|
|
cellsToRemove[cell] = cell
|
|
end
|
|
end
|
|
|
|
local i = 1
|
|
while i <= #boxCells do
|
|
if boxCells[i] == cellsToRemove[boxCells[i]] then
|
|
table.remove(boxCells, i)
|
|
else
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
return boxCells
|
|
end
|