implement hp and mana bars
This commit is contained in:
parent
73ba99734c
commit
bc730ef48c
20
lib/simple_ui/color.lua
Normal file
20
lib/simple_ui/color.lua
Normal file
@ -0,0 +1,20 @@
|
||||
--- @class Color
|
||||
--- @field r number
|
||||
--- @field g number
|
||||
--- @field b number
|
||||
--- @field a number
|
||||
local color = {
|
||||
r = 1,
|
||||
g = 1,
|
||||
b = 1,
|
||||
a = 1
|
||||
}
|
||||
color.__index = color
|
||||
|
||||
--- @param rgba {r?: number, g?: number, b?: number, a?: number}
|
||||
--- @return Color
|
||||
function color.new(rgba)
|
||||
return setmetatable(rgba, color)
|
||||
end
|
||||
|
||||
return color.new
|
||||
@ -33,7 +33,7 @@ end
|
||||
--- @return T
|
||||
function uiElement.new(self, values)
|
||||
values.bounds = values.bounds or Rect {}
|
||||
values.overlayGradientMesh = values.overlayGradientMesh or uiElement.bounds;
|
||||
values.overlayGradientMesh = values.overlayGradientMesh or uiElement.overlayGradientMesh;
|
||||
return setmetatable(values, self)
|
||||
end
|
||||
|
||||
|
||||
@ -3,13 +3,19 @@ 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()
|
||||
@ -17,20 +23,54 @@ function barElement:update(dt)
|
||||
end
|
||||
|
||||
function barElement:draw()
|
||||
love.graphics.push()
|
||||
love.graphics.applyTransform(self.transform)
|
||||
local valueWidth = self.bounds.width * self.value / self.maxValue
|
||||
local emptyWidth = self.bounds.width - valueWidth
|
||||
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
--- шум
|
||||
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.rectangle("fill", self.bounds.x, self.bounds.y, self.bounds.width * self.value / self.maxValue,
|
||||
--- закраска пустой части
|
||||
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)
|
||||
love.graphics.pop()
|
||||
--- текст поверх
|
||||
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:drawGradientOverlay()
|
||||
end
|
||||
|
||||
--- @class BottomBars : UIElement
|
||||
--- @field children BarElement[]
|
||||
--- @field hpBar BarElement
|
||||
--- @field manaBar BarElement
|
||||
local bottomBars = setmetatable({}, Element)
|
||||
bottomBars.__index = bottomBars;
|
||||
|
||||
@ -38,7 +78,7 @@ bottomBars.__index = bottomBars;
|
||||
function bottomBars.new(cid)
|
||||
local t = setmetatable({}, bottomBars)
|
||||
|
||||
t.children = {
|
||||
t.hpBar =
|
||||
barElement:new {
|
||||
getter = function()
|
||||
local char = Tree.level.characters[cid]
|
||||
@ -46,9 +86,12 @@ function bottomBars.new(cid)
|
||||
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]
|
||||
@ -56,63 +99,154 @@ function bottomBars.new(cid)
|
||||
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 padding = 8
|
||||
local screenW, screenH = love.graphics.getDimensions()
|
||||
self.bounds = Rect {
|
||||
height = 40 + 2 * padding,
|
||||
width = screenW * 0.25,
|
||||
y = screenH - 64 - 1 - 2 * padding - 40
|
||||
local height = 14
|
||||
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,
|
||||
x = self.bounds.x + margin,
|
||||
y = self.bounds.y
|
||||
}
|
||||
|
||||
self.transform = love.math.newTransform():translate(-self.bounds.width / 2 + screenW / 2, self.bounds.y)
|
||||
|
||||
for i = 1, #self.children do
|
||||
self.children[i].bounds = Rect {
|
||||
width = screenW * 0.25,
|
||||
height = 20
|
||||
self.manaBar.bounds = Rect {
|
||||
width = -2 * margin + self.bounds.width / 2,
|
||||
height = height,
|
||||
x = self.bounds.x + margin + self.bounds.width / 2,
|
||||
y = self.bounds.y
|
||||
}
|
||||
self.children[i].transform = self.transform:clone():translate(0,
|
||||
self.children[i].bounds.height * (i - 1) + (i - 1) * padding)
|
||||
end
|
||||
|
||||
|
||||
for _, el in ipairs(self.children) do
|
||||
el:update(dt)
|
||||
end
|
||||
self.hpBar:update(dt)
|
||||
self.manaBar:update(dt)
|
||||
end
|
||||
|
||||
function bottomBars:draw()
|
||||
for _, el in ipairs(self.children) do
|
||||
el:draw()
|
||||
end
|
||||
-- шум
|
||||
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
|
||||
|
||||
local c = love.graphics.newCanvas(1280, 720) --- @TODO: выставлять канвасу правильный размер в зависимости от окна
|
||||
|
||||
--- @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
|
||||
|
||||
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
|
||||
}
|
||||
end
|
||||
|
||||
function characterPanel:draw()
|
||||
love.graphics.setCanvas(c)
|
||||
love.graphics.clear()
|
||||
self.skillRow:draw()
|
||||
self.bars:draw()
|
||||
|
||||
self:drawBorder("outer")
|
||||
|
||||
local alpha = 1
|
||||
if self.state == "show" then
|
||||
alpha = self.animationNode:getValue()
|
||||
elseif self.state == "hide" then
|
||||
alpha = 1 - self.animationNode:getValue()
|
||||
end
|
||||
|
||||
love.graphics.setCanvas()
|
||||
love.graphics.setColor(1, 1, 1, alpha)
|
||||
love.graphics.draw(c)
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
end
|
||||
|
||||
-----------------------------------
|
||||
local layout = {}
|
||||
function layout:update(dt)
|
||||
local cid = Tree.level.selector:selected()
|
||||
if cid then
|
||||
self.skillRow = SkillRow(cid)
|
||||
self.skillRow:show()
|
||||
-- self.bottomBars = bottomBars.new(cid)
|
||||
self.characterPanel = characterPanel.new(cid)
|
||||
self.characterPanel:show()
|
||||
elseif Tree.level.selector:deselected() then
|
||||
self.skillRow:hide()
|
||||
-- self.bottomBars = nil
|
||||
self.characterPanel:hide()
|
||||
end
|
||||
if self.skillRow then self.skillRow:update(dt) end
|
||||
-- if self.bottomBars then self.bottomBars:update(dt) end
|
||||
if self.characterPanel then self.characterPanel:update(dt) end
|
||||
end
|
||||
|
||||
function layout:draw()
|
||||
if self.skillRow then self.skillRow:draw() end
|
||||
-- if self.bottomBars then self.bottomBars:draw() end
|
||||
if self.characterPanel then self.characterPanel:draw() end
|
||||
end
|
||||
|
||||
return layout
|
||||
|
||||
@ -63,8 +63,6 @@ end
|
||||
--- @class SkillRow : UIElement
|
||||
--- @field characterId Id
|
||||
--- @field selected SkillButton?
|
||||
--- @field animationNode AnimationNode
|
||||
--- @field state "show" | "idle" | "hide"
|
||||
--- @field children SkillButton[]
|
||||
local skillRow = setmetatable({}, Element)
|
||||
skillRow.__index = skillRow
|
||||
@ -74,7 +72,6 @@ skillRow.__index = skillRow
|
||||
function skillRow.new(characterId)
|
||||
local t = {
|
||||
characterId = characterId,
|
||||
state = "show",
|
||||
children = {}
|
||||
}
|
||||
|
||||
@ -85,7 +82,6 @@ function skillRow.new(characterId)
|
||||
for i, spell in ipairs(behavior.spellbook) do
|
||||
local skb = skillButton:new { icon = spell.tag }
|
||||
skb.onClick = function()
|
||||
if t.state ~= "idle" then return end
|
||||
skb.selected = not skb.selected
|
||||
if t.selected then t.selected.selected = false end
|
||||
t.selected = skb
|
||||
@ -109,36 +105,7 @@ function skillRow.new(characterId)
|
||||
return t
|
||||
end
|
||||
|
||||
function skillRow: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 skillRow: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
|
||||
|
||||
function skillRow:update(dt)
|
||||
if self.animationNode then self.animationNode:update(dt) end
|
||||
|
||||
local iconSize = 64 * UI_SCALE
|
||||
local screenW, screenH = love.graphics.getDimensions()
|
||||
local padding, margin = 8, 4
|
||||
@ -161,6 +128,7 @@ end
|
||||
local c = love.graphics.newCanvas(1280, 720) --- @TODO: выставлять канвасу правильный размер в зависимости от окна
|
||||
|
||||
function skillRow:draw()
|
||||
local oldCanvas = love.graphics.getCanvas()
|
||||
love.graphics.setCanvas({ c, stencil = true })
|
||||
love.graphics.clear()
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
@ -195,24 +163,13 @@ function skillRow:draw()
|
||||
love.graphics.rectangle("fill", self.bounds.x, self.bounds.y, self.bounds.width, self.bounds.height)
|
||||
love.graphics.setBlendMode("alpha")
|
||||
|
||||
--граница
|
||||
self:drawBorder("outer")
|
||||
|
||||
love.graphics.setStencilTest()
|
||||
|
||||
--затенение
|
||||
self:drawGradientOverlay()
|
||||
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
love.graphics.setCanvas()
|
||||
|
||||
local alpha = 1
|
||||
if self.state == "show" then
|
||||
alpha = self.animationNode:getValue()
|
||||
elseif self.state == "hide" then
|
||||
alpha = 1 - self.animationNode:getValue()
|
||||
end
|
||||
love.graphics.setColor(1, 1, 1, alpha)
|
||||
love.graphics.setCanvas(oldCanvas)
|
||||
love.graphics.draw(c)
|
||||
end
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user