Files
2026-10-09 16:33:06 -04:00

78 lines
3.4 KiB
Lua

local DonBGBase = require("background/bg_objects/donbg/base")
-- SparkleDonBG: a DonBGBase band whose clear set has stars twinkling in clusters over it
-- (still, not scrolling), as in IMAS SideM and Love Live!. Both ensos place the clusters the
-- same way and time the stars the same way; only the star sizes differ, so each collab gives
-- its two star sets. Ambient, in ms.
--
-- Twinkles in a 2s cycle, counted in Lumen frames (120 a cycle): { pop, life, x, y, from, to }.
-- A star pops up to `from` size in 5 frames, grows to `to` until `life` frames after the pop
-- and shrinks away in 5 more. x, y: offset from the cluster's centre.
-- stars = { trio = (three stars taking turns), pair = (one star in the middle, the other
-- hopping between two spots) }; texture key "sparkle" is the 55px star.
local SPARKLE_MS, SPARKLE_FRAMES, SPARKLE_POP = 2000, 120, 5
local SPARKLE_PIVOT = 27.5 -- the star's centre in its image
-- clusters: { set, x, y, size } (a negative size turns the cluster round)
local CLUSTERS = {
{ "trio", 54.5, 28.5, 1 }, { "trio", 413.7, 32.7, -0.8 }, { "trio", 795.7, 170.2, 0.8 },
{ "trio", 228.75, 163.6, 0.5 }, { "trio", 578.95, 162.5, 1 }, { "trio", 894.4, 102, 0.5 },
{ "trio", 1057.45, 48, -1 }, { "trio", 1179.45, 117.1, 0.5 }, { "trio", 1292.45, 162.5, 1 },
{ "pair", 38.3, 114.35, 1 }, { "pair", 546.4, 44.35, 1 }, { "pair", 959, 148.4, 1 },
}
-- size and opacity of a twinkle `f` frames into the cycle (nil while it's hidden)
local function twinkle(s, f)
local pop, life, from, to = s[1], s[2], s[5], s[6]
local u = (f - pop) % SPARKLE_FRAMES
if u < SPARKLE_POP then return from * u / SPARKLE_POP, u / SPARKLE_POP end
if u < life then return from + (to - from) * (u - SPARKLE_POP) / (life - SPARKLE_POP), 1 end
if u < life + SPARKLE_POP then
local k = 1 - (u - life) / SPARKLE_POP
return to * k, 0.8 * k
end
end
local SparkleDonBG = setmetatable({}, { __index = DonBGBase })
SparkleDonBG.__index = SparkleDonBG
function SparkleDonBG.new(player_num, path, spec, stars)
local self = setmetatable(DonBGBase.new(1, player_num, path, spec), SparkleDonBG)
self._id_sparkle = tex.get_texture(path .. "/" .. self.name .. "/" .. "sparkle") or 0
self.sparkle_size = tex.get_texture_info(self.name, "sparkle").width
self.stars = stars
self.now = 0
return self
end
function SparkleDonBG:update(current_time_ms, bpm)
DonBGBase.update(self, current_time_ms, bpm)
self.now = current_time_ms
end
function SparkleDonBG:draw_band(y)
DonBGBase.draw_band(self, y)
if self.clear <= 0 then return end
local sc, w = tex.get_screen_scale(), self.sparkle_size
local f = (self.now % SPARKLE_MS) * SPARKLE_FRAMES / SPARKLE_MS
for _, c in ipairs(CLUSTERS) do
local k = c[4]
for _, s in ipairs(self.stars[c[1]]) do
local size, alpha = twinkle(s, f)
if size and size > 0 then
size = size * math.abs(k)
local o = SPARKLE_PIVOT * size * sc
tex.draw_texture(self._id_sparkle, {
x = (c[2] + s[3] * k) * sc, y = y + (c[3] + s[4] * k) * sc,
x2 = w * (size - 1), y2 = w * (size - 1), origin = { o, o },
fade = alpha * self.clear,
})
end
end
end
end
function SparkleDonBG:draw(y) self:draw_dark(SparkleDonBG.draw_band, y or 0) end
return SparkleDonBG