101 lines
3.2 KiB
Lua

--- @class ShadowcasterBehavior : Behavior
local behavior = {}
behavior.id = "shadowcaster"
behavior.__index = behavior
function behavior.new() return setmetatable({}, behavior) end
local function makeGradientMesh(w, h, topColor, bottomColor)
local vertices = {
{ 0, 0, 0, 0, topColor[1], topColor[2], topColor[3], topColor[4] }, -- левый верх
{ w, 0, 1, 0, topColor[1], topColor[2], topColor[3], topColor[4] }, -- правый верх
{ w + w * 0.1, h, 1, 1, bottomColor[1], bottomColor[2], bottomColor[3], bottomColor[4] }, -- правый низ
{ 0 - w * 0.1, h, 0, 1, bottomColor[1], bottomColor[2], bottomColor[3], bottomColor[4] }, -- левый низ
}
local mesh = love.graphics.newMesh(vertices, "fan", "static")
return mesh
end
--- @param phi number угол, под которым падает свет
--- @return boolean, number: рисуем ли тень * её прозрачность
local function getFakeShadow(phi)
local pi = math.pi
if phi <= pi / 4 then
-- 1
return false, 1
end
if phi <= pi / 2 then
-- 2
return true, 1 - (phi - pi / 4) / (pi / 4)
end
if phi <= 3 * pi / 4 then
-- 3
return true, (phi - pi / 2) / (pi / 4)
end
if phi <= 5 * pi / 4 then
-- 4
return false, 1
end
if phi <= 3 * pi / 2 then
-- 5
return true, 1 - (phi - 5 * pi / 4) / (pi / 4)
end
if phi <= 7 * pi / 4 then
-- 6
return true, (phi - 3 * pi / 2) / (pi / 4)
end
-- 1
return false, 1
end
function behavior:draw()
local sprite = self.owner:has(Tree.behaviors.sprite)
local map = self.owner:has(Tree.behaviors.map)
if not map then return end
local ppm = Tree.level.camera.pixelsPerMeter
local position = map.displayedPosition + Vec3 { 0.5, 0.5 }
love.graphics.setCanvas(Tree.level.render.shadowLayer)
love.graphics.push()
love.graphics.scale(ppm)
love.graphics.setColor(0, 0, 0, 0.5)
love.graphics.translate(position.x, position.y)
love.graphics.ellipse("fill", 0, 0, 0.2, 0.2 * math.cos(math.pi / 4))
if not sprite then
love.graphics.pop()
return
end
local phi = love.timer.getTime() % (2 * math.pi)
local drawFakeShadow, opacity = getFakeShadow(phi)
local nangle = (math.pi + phi) % (2 * math.pi)
love.graphics.rotate(nangle)
love.graphics.setColor(0, 0, 0, math.min(opacity * opacity, 0.5))
sprite.animationTable[sprite.state]:draw(Tree.assets.files.sprites.character[sprite.state],
0,
0, nil, ((nangle >= math.pi / 2 and nangle < (3 * math.pi / 2)) and -1 or 1) / ppm * sprite.side,
1.2 / ppm,
38, 47)
if drawFakeShadow then
love.graphics.setColor(0, 0, 0, 1)
local mesh = makeGradientMesh(0.4, 1, { 0, 0, 0, 0.15 },
{ 0, 0, 0, 0.0 })
love.graphics.push()
love.graphics.rotate(math.pi)
love.graphics.translate(-0.2, 0)
love.graphics.draw(mesh)
love.graphics.pop()
end
love.graphics.pop()
love.graphics.setColor(1, 1, 1)
love.graphics.setCanvas()
end
return behavior