280 lines
8.6 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local easing = require "lib.utils.easing"
local AnimationNode = require "lib.animation_node"
local Element = require "lib.simple_ui.element"
local Rect = require "lib.simple_ui.rect"
local SkillRow = require "lib.simple_ui.level.skill_row"
local Color = require "lib.simple_ui.color"
--- @class BarElement : UIElement
--- @field getter fun() : number
--- @field value number
--- @field maxValue number
--- @field color Color
--- @field useDividers boolean
--- @field drawText boolean
local barElement = setmetatable({}, Element)
barElement.__index = barElement
barElement.useDividers = false
barElement.drawText = false
function barElement:update(dt)
local val = self.getter()
self.value = val < 0 and 0 or val > self.maxValue and self.maxValue or val
end
function barElement:draw()
local valueWidth = self.bounds.width * self.value / self.maxValue
local emptyWidth = self.bounds.width - valueWidth
--- шум
love.graphics.setShader(Tree.assets.files.shaders.soft_uniform_noise)
love.graphics.rectangle("fill", self.bounds.x, self.bounds.y, self.bounds.width, self.bounds.height)
love.graphics.setShader()
--- закраска пустой части
love.graphics.setColor(0.05, 0.05, 0.05)
love.graphics.setBlendMode("multiply", "premultiplied")
love.graphics.rectangle("fill", self.bounds.x + valueWidth, self.bounds.y, emptyWidth,
self.bounds.height)
love.graphics.setBlendMode("alpha")
--- закраска значимой части её цветом
love.graphics.setColor(self.color.r, self.color.g, self.color.b)
love.graphics.setBlendMode("multiply", "premultiplied")
love.graphics.rectangle("fill", self.bounds.x, self.bounds.y, valueWidth,
self.bounds.height)
love.graphics.setBlendMode("alpha")
--- мерки
love.graphics.setColor(38 / 255, 50 / 255, 56 / 255)
if self.useDividers then
local count = self.maxValue - 1
local measureWidth = self.bounds.width / self.maxValue
for i = 1, count, 1 do
love.graphics.line(self.bounds.x + i * measureWidth, self.bounds.y, self.bounds.x + i * measureWidth,
self.bounds.y + self.bounds.height)
end
end
love.graphics.setColor(1, 1, 1)
--- текст поверх
if self.drawText then
love.graphics.printf(tostring(self.value) .. "/" .. tostring(self.maxValue), self.bounds.x,
self.bounds.y, self.bounds.width, "center")
end
self:drawBorder("inner")
self:drawGradientOverlay()
end
--- @class BottomBars : UIElement
--- @field hpBar BarElement
--- @field manaBar BarElement
local bottomBars = setmetatable({}, Element)
bottomBars.__index = bottomBars;
--- @param cid Id
function bottomBars.new(cid)
local t = setmetatable({}, bottomBars)
t.hpBar =
barElement:new {
getter = function()
local char = Tree.level.characters[cid]
return char:try(Tree.behaviors.stats, function(stats)
return stats.hp or 0
end)
end,
color = Color { r = 130 / 255, g = 8 / 255, b = 8 / 255 },
drawText = true,
maxValue = 20
}
t.manaBar =
barElement:new {
getter = function()
local char = Tree.level.characters[cid]
return char:try(Tree.behaviors.stats, function(stats)
return stats.mana or 0
end)
end,
color = Color { r = 51 / 255, g = 105 / 255, b = 30 / 255 },
useDividers = true,
maxValue = 10
}
return t
end
function bottomBars:update(dt)
local height = 16
local margin = 2
self.bounds.height = height
self.bounds.y = self.bounds.y - height
self.hpBar.bounds = Rect {
width = -2 * margin + self.bounds.width / 2,
height = height - margin,
x = self.bounds.x + margin,
y = self.bounds.y + margin
}
self.manaBar.bounds = Rect {
width = -2 * margin + self.bounds.width / 2,
height = height - margin,
x = self.bounds.x + margin + self.bounds.width / 2,
y = self.bounds.y + margin
}
self.hpBar:update(dt)
self.manaBar:update(dt)
end
function bottomBars:draw()
-- шум
love.graphics.setShader(Tree.assets.files.shaders.soft_uniform_noise)
love.graphics.rectangle("fill", self.bounds.x, self.bounds.y, self.bounds.width, self.bounds.height)
love.graphics.setShader()
love.graphics.setColor(38 / 255, 50 / 255, 56 / 255)
love.graphics.setBlendMode("multiply", "premultiplied")
love.graphics.rectangle("fill", self.bounds.x, self.bounds.y, self.bounds.width, self.bounds.height)
love.graphics.setBlendMode("alpha")
self.hpBar:draw()
self.manaBar:draw()
end
--- @class CharacterPanel : UIElement
--- @field animationNode AnimationNode
--- @field state "show" | "idle" | "hide"
--- @field skillRow SkillRow
--- @field bars BottomBars
local characterPanel = setmetatable({}, Element)
characterPanel.__index = characterPanel
function characterPanel.new(characterId)
local t = {}
t.state = "show"
t.skillRow = SkillRow(characterId)
t.bars = bottomBars.new(characterId)
return setmetatable(t, characterPanel)
end
function characterPanel:show()
AnimationNode {
function(animationNode)
if self.animationNode then self.animationNode:finish() end
self.animationNode = animationNode
self.state = "show"
end,
duration = 300,
onEnd = function()
self.state = "idle"
end,
easing = easing.easeOutCubic
}:run()
end
function characterPanel:hide()
AnimationNode {
function(animationNode)
if self.animationNode then self.animationNode:finish() end
self.animationNode = animationNode
self.state = "hide"
end,
duration = 300,
easing = easing.easeOutCubic
}:run()
end
--- @type love.Canvas
local characterPanelCanvas;
function characterPanel:update(dt)
if self.animationNode then self.animationNode:update(dt) end
self.skillRow:update(dt)
self.bars.bounds = Rect {
width = self.skillRow.bounds.width,
x = self.skillRow.bounds.x,
y = self.skillRow.bounds.y
}
self.bars:update(dt)
self.bounds = Rect {
x = self.bars.bounds.x,
y = self.bars.bounds.y,
width = self.bars.bounds.width,
height = self.bars.bounds.height + self.skillRow.bounds.height
}
if not characterPanelCanvas then
characterPanelCanvas = love.graphics.newCanvas(self.bounds.width, self.bounds.height)
end
--- анимация появления
local alpha = 1
if self.state == "show" then
alpha = self.animationNode:getValue()
elseif self.state == "hide" then
alpha = 1 - self.animationNode:getValue()
end
local revealShader = Tree.assets.files.shaders.reveal
revealShader:send("t", alpha)
end
function characterPanel:draw()
self.skillRow:draw()
--- @TODO: переписать этот ужас с жонглированием координатами, а то слишком хардкод (skillRow рисуется относительно нуля и не закрывает канвас)
love.graphics.push()
local canvas = love.graphics.getCanvas()
love.graphics.translate(0, self.bars.bounds.height)
love.graphics.setCanvas(characterPanelCanvas)
love.graphics.clear()
love.graphics.draw(canvas)
love.graphics.pop()
love.graphics.push()
love.graphics.translate(-self.bounds.x, -self.bounds.y)
self.bars:draw()
self:drawBorder("outer")
love.graphics.pop()
--- рисуем текстуру шейдером появления
love.graphics.setCanvas()
love.graphics.setShader(Tree.assets.files.shaders.reveal)
love.graphics.setColor(1, 1, 1, 1)
love.graphics.push()
love.graphics.translate(self.bounds.x, self.bounds.y)
love.graphics.draw(characterPanelCanvas)
love.graphics.setColor(1, 1, 1)
love.graphics.pop()
love.graphics.setShader()
end
-----------------------------------
local layout = {}
function layout:update(dt)
local cid = Tree.level.selector:selected()
if cid then
self.characterPanel = characterPanel.new(cid)
self.characterPanel:show()
elseif Tree.level.selector:deselected() then
self.characterPanel:hide()
end
if self.characterPanel then self.characterPanel:update(dt) end
end
function layout:draw()
if self.characterPanel then self.characterPanel:draw() end
end
return layout