diff --git a/assets/shaders/soft_uniform_noise.glsl b/assets/shaders/soft_uniform_noise.glsl new file mode 100644 index 0000000..6cdba61 --- /dev/null +++ b/assets/shaders/soft_uniform_noise.glsl @@ -0,0 +1,17 @@ +#pragma language glsl3 + +vec2 hash(vec2 p) { + p = fract(p * vec2(123.34, 456.21)); + p += dot(p, p + 34.345); + return fract(vec2(p.x * p.y, p.x + p.y)); +} + +vec4 effect(vec4 color, Image tex, vec2 uv, vec2 px) +{ + vec2 cell = floor(px / 2.0); + + float n = hash(cell).x; // 0..1 + float v = 0.9 + n * 0.2; // 0.9..1.0 + + return vec4(v, v, v, 1.0); +} diff --git a/lib/simple_ui/element.lua b/lib/simple_ui/element.lua index b2433c0..4593a57 100644 --- a/lib/simple_ui/element.lua +++ b/lib/simple_ui/element.lua @@ -11,8 +11,7 @@ function uiElement:update(dt) end function uiElement:draw() end function uiElement:hitTest(screenX, screenY) - local lx, ly = self.transform:inverseTransformPoint(screenX, screenY) - return self.bounds:hasPoint(lx, ly) + return self.bounds:hasPoint(screenX, screenY) end --- @generic T : UIElement @@ -21,8 +20,43 @@ end --- @return T function uiElement.new(self, values) values.bounds = values.bounds or Rect {} - values.transform = values.transform or love.math.newTransform() return setmetatable(values, self) end +--- Рисует границу вокруг элемента (с псевдо-затенением) +--- @param type "outer" | "inner" +function uiElement:drawBorder(type) + if type == "inner" then + love.graphics.setColor(0.2, 0.2, 0.2) + love.graphics.line({ + self.bounds.x, self.bounds.y + self.bounds.height, + self.bounds.x, self.bounds.y, + self.bounds.x + self.bounds.width, self.bounds.y, + }) + + love.graphics.setColor(0.3, 0.3, 0.3) + love.graphics.line({ + self.bounds.x + self.bounds.width, self.bounds.y, + self.bounds.x + self.bounds.width, self.bounds.y + self.bounds.height, + self.bounds.x, self.bounds.y + self.bounds.height, + }) + else + love.graphics.setColor(0.2, 0.2, 0.2) + love.graphics.line({ + self.bounds.x + self.bounds.width, self.bounds.y, + self.bounds.x + self.bounds.width, self.bounds.y + self.bounds.height, + self.bounds.x, self.bounds.y + self.bounds.height, + }) + + love.graphics.setColor(0.3, 0.3, 0.3) + love.graphics.line({ + self.bounds.x, self.bounds.y + self.bounds.height, + self.bounds.x, self.bounds.y, + self.bounds.x + self.bounds.width, self.bounds.y, + }) + end + + love.graphics.setColor(1, 1, 1) +end + return uiElement diff --git a/lib/simple_ui/level/layout.lua b/lib/simple_ui/level/layout.lua index 4fdfe14..a385f8b 100644 --- a/lib/simple_ui/level/layout.lua +++ b/lib/simple_ui/level/layout.lua @@ -64,26 +64,26 @@ function bottomBars.new(cid) end function bottomBars:update(dt) - local padding = 16 + local padding = 8 local screenW, screenH = love.graphics.getDimensions() self.bounds = Rect { - height = 10, - width = 200 + 200 + padding, - y = screenH - 96 - padding + height = 40 + 2 * padding, + width = screenW * 0.25, + y = screenH - 64 - 1 - 2 * padding - 40 } 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 = 200, + width = screenW * 0.25, height = 20 } - self.children[i].transform = self.transform:clone():translate(padding * (i - 1) + (i - 1) * 200, 0) + 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 @@ -101,18 +101,18 @@ function layout:update(dt) if cid then self.skillRow = SkillRow(cid) self.skillRow:show() - self.bottomBars = bottomBars.new(cid) + -- self.bottomBars = bottomBars.new(cid) elseif Tree.level.selector:deselected() then self.skillRow:hide() - self.bottomBars = nil + -- self.bottomBars = nil end if self.skillRow then self.skillRow:update(dt) end - if self.bottomBars then self.bottomBars:update(dt) end + -- if self.bottomBars then self.bottomBars: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.bottomBars then self.bottomBars:draw() end end return layout diff --git a/lib/simple_ui/level/scale.lua b/lib/simple_ui/level/scale.lua new file mode 100644 index 0000000..c2b6807 --- /dev/null +++ b/lib/simple_ui/level/scale.lua @@ -0,0 +1,2 @@ +local UI_SCALE = 0.8 -- выдуманное значение для dependency injection +return UI_SCALE diff --git a/lib/simple_ui/level/skill_row.lua b/lib/simple_ui/level/skill_row.lua index ab9a9c9..aa0e92a 100644 --- a/lib/simple_ui/level/skill_row.lua +++ b/lib/simple_ui/level/skill_row.lua @@ -4,15 +4,18 @@ local AnimationNode = require "lib.animation_node" local Element = require "lib.simple_ui.element" local Rect = require "lib.simple_ui.rect" +local UI_SCALE = require "lib.simple_ui.level.scale" + --- @class SkillButton : UIElement --- @field hovered boolean --- @field selected boolean --- @field onClick function? ---- @field icon string +--- @field icon? string local skillButton = setmetatable({}, Element) skillButton.__index = skillButton function skillButton:update(dt) + if not self.icon then return end local mx, my = love.mouse.getPosition() if self:hitTest(mx, my) then self.hovered = true @@ -26,22 +29,32 @@ function skillButton:update(dt) end function skillButton:draw() - love.graphics.push() - love.graphics.applyTransform(self.transform) + love.graphics.setLineWidth(2) - local r, g, b, a = love.graphics.getColor() - if self.selected then - love.graphics.setColor(0.3, 1, 0.3, a) - elseif self.hovered then - love.graphics.setColor(0.7, 1, 0.7, a) - else - love.graphics.setColor(1, 1, 1, a) + if not self.icon then + love.graphics.setColor(0.05, 0.05, 0.05) + love.graphics.rectangle("fill", self.bounds.x, self.bounds.y, self.bounds.width, self.bounds.height) + self:drawBorder("inner") + return end - love.graphics.translate(0, self.bounds.y) - love.graphics.draw(icons.atlas, icons:pickQuad(self.icon)) + if self.selected then + love.graphics.setColor(0.3, 1, 0.3) + elseif self.hovered then + love.graphics.setColor(0.7, 1, 0.7) + else + love.graphics.setColor(1, 1, 1) + end + + local quad = icons:pickQuad(self.icon) + love.graphics.push() + love.graphics.translate(self.bounds.x, self.bounds.y) + love.graphics.scale(self.bounds.width / icons.tileSize, self.bounds.height / icons.tileSize) + love.graphics.draw(icons.atlas, quad) love.graphics.pop() + + self:drawBorder("inner") end -------------------------------------------------------------------------------- @@ -88,6 +101,10 @@ function skillRow.new(characterId) end end) + for i = #t.children + 1, 7, 1 do + t.children[i] = skillButton:new {} + end + return t end @@ -121,32 +138,51 @@ end function skillRow:update(dt) if self.animationNode then self.animationNode:update(dt) end - local iconSize = icons.tileSize - local scale = (64 / iconSize) + local iconSize = 64 * UI_SCALE local screenW, screenH = love.graphics.getDimensions() - local padding = 8 - local count = #self.children + local padding, margin = 8, 4 + local count = #self.children -- слоты под скиллы self.bounds = Rect { - width = count * icons.tileSize + (count - 1) * padding, - height = iconSize, - y = self.state == "show" and 10 * (1 - self.animationNode:getValue()) or 0 + width = iconSize * count + (count + 1) * margin, + height = iconSize + 2 * margin, } - self.transform = love.math.newTransform():translate(screenW / 2, - screenH - 16):scale(scale, scale):translate(-self.bounds.width / 2, -iconSize) + self.bounds.y = screenH - self.bounds.height - padding -- отступ снизу + self.bounds.x = screenW / 2 - self.bounds.width / 2 for i, skb in ipairs(self.children) do - skb.bounds = Rect { height = iconSize, width = iconSize } - skb.transform = self.transform:clone():translate(self.bounds.x + (i - 1) * iconSize + - (i - 1) * - padding, -- левый край ряда + размер предыдущих иконок + размер предыдущих отступов - self.bounds.y -- высота не меняется - ) + skb.bounds = Rect { x = self.bounds.x + margin + (i - 1) * (iconSize + margin), -- друг за другом, включая первый отступ от границы + y = self.bounds.y + margin, height = iconSize, width = iconSize } skb:update(dt) end end +local c = love.graphics.newCanvas(1280, 720) --- @TODO: выставлять канвасу правильный размер в зависимости от окна + function skillRow:draw() + love.graphics.setCanvas(c) + love.graphics.clear() + -- шум + 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:drawBorder("outer") + + love.graphics.setColor(1, 1, 1) + for _, skb in ipairs(self.children) do + skb:draw() + end + + love.graphics.setCanvas() + local alpha = 1 if self.state == "show" then alpha = self.animationNode:getValue() @@ -154,9 +190,7 @@ function skillRow:draw() alpha = 1 - self.animationNode:getValue() end love.graphics.setColor(1, 1, 1, alpha) - for _, skb in ipairs(self.children) do - skb:draw() - end + love.graphics.draw(c) end return skillRow.new diff --git a/lib/simple_ui/rect.lua b/lib/simple_ui/rect.lua index 3f3931f..932a0ad 100644 --- a/lib/simple_ui/rect.lua +++ b/lib/simple_ui/rect.lua @@ -18,7 +18,7 @@ function rect.new(table) end function rect:hasPoint(x, y) - return x >= self.x and x < self.width and y >= self.y and y < self.height + return x >= self.x and x < self.x + self.width and y >= self.y and y < self.y + self.height end return rect.new diff --git a/main.lua b/main.lua index 26825d5..603cfd8 100644 --- a/main.lua +++ b/main.lua @@ -18,7 +18,7 @@ function love.load() end Tree.level.turnOrder:endRound() print("Now playing:", Tree.level.turnOrder.current) - love.window.setMode(1080, 720, { resizable = true, msaa = 4, vsync = true }) + love.window.setMode(1280, 720, { resizable = false, msaa = 0, vsync = true }) end local lt = "0"