121 lines
4.8 KiB
Lua
121 lines
4.8 KiB
Lua
local Timing = require("background/bg_objects/timing")
|
|
|
|
local chain_moves, sum = Timing.chain_moves, Timing.sum
|
|
|
|
-- Clear background with falling petals (A3, Touken Ranbu): drawn over the normal one, which
|
|
-- stays underneath. A haze fades in over `haze_in` beats; a beat in, the petal streams fade in
|
|
-- over half a beat. Losing clear fades the haze out over `haze_out` beats and the petals over
|
|
-- `petals_out`. Transitions in beats.
|
|
-- Each stream is three tiles (texture.json indices `first`.. of its `key`) drifting by
|
|
-- `dx`, `dy` over a `flight` (ms); a new pass starts every half flight, so two are on screen.
|
|
-- `warm` streams start with both passes showing (Lumen places the second at frame 0);
|
|
-- `fade_out` fades a pass over the second half of its flight; `rotation` turns each tile
|
|
-- about its centre (`half` px in).
|
|
-- spec: { path, haze = { key, blend }, haze_in, haze_out, petals_out, streams }
|
|
|
|
-- A value in thousandths that eases from wherever it is to a target (fade in/out envelopes)
|
|
local function envelope(current, moves, unit)
|
|
return { offset = current, moves = chain_moves(moves, unit, 1) }
|
|
end
|
|
local function env_value(env) return env.offset + sum(env.moves) end
|
|
local function env_update(env, current_time_ms)
|
|
for _, m in ipairs(env.moves) do m:update(current_time_ms) end
|
|
end
|
|
|
|
local PETALS_IN = { { 1, 0 }, { 0.5, 1000 } }
|
|
local TILES = 3
|
|
|
|
local PetalFever = {}
|
|
PetalFever.__index = PetalFever
|
|
|
|
function PetalFever.new(bpm, spec)
|
|
local self = setmetatable({}, PetalFever)
|
|
self.spec = spec
|
|
self.name = "bg_fever_0"
|
|
tex.load_folder(spec.path, "bg_fever/" .. self.name)
|
|
local function id(key) return tex.get_texture(spec.path .. "/" .. self.name .. "/" .. key) or 0 end
|
|
self._id_haze = id(spec.haze.key)
|
|
self._ids = {}
|
|
for i, stream in ipairs(spec.streams) do self._ids[i] = id(stream.key) end
|
|
self.beat = 60000 / bpm
|
|
self.haze = envelope(0, {}, 1)
|
|
self.petals = envelope(0, {}, 1)
|
|
self.streams = {}
|
|
return self
|
|
end
|
|
|
|
local function new_pass(stream, delay)
|
|
local half = anim.move(stream.flight / 2, { total_distance = 1000, delay = delay })
|
|
half:start()
|
|
return half
|
|
end
|
|
|
|
function PetalFever:start()
|
|
local haze, petals = env_value(self.haze), env_value(self.petals)
|
|
self.haze = envelope(haze, { { self.spec.haze_in, 1000 - haze } }, self.beat)
|
|
self.petals = envelope(petals, { PETALS_IN[1], { PETALS_IN[2][1], 1000 - petals } }, self.beat)
|
|
-- the streams start over as the petals begin to fade in
|
|
for i, stream in ipairs(self.spec.streams) do
|
|
self.streams[i] = { half = new_pass(stream, PETALS_IN[1][1] * self.beat), laps = stream.warm and 1 or 0 }
|
|
end
|
|
end
|
|
|
|
function PetalFever:stop()
|
|
local haze, petals = env_value(self.haze), env_value(self.petals)
|
|
self.haze = envelope(haze, { { self.spec.haze_out, -haze } }, self.beat)
|
|
self.petals = envelope(petals, { { self.spec.petals_out, -petals } }, self.beat)
|
|
end
|
|
|
|
function PetalFever:update(current_time_ms, bpm)
|
|
if bpm then self.beat = 60000 / bpm end
|
|
env_update(self.haze, current_time_ms)
|
|
env_update(self.petals, current_time_ms)
|
|
for i, s in pairs(self.streams) do
|
|
s.half:update(current_time_ms)
|
|
if s.half.is_finished then
|
|
s.half = new_pass(self.spec.streams[i])
|
|
s.laps = s.laps + 1
|
|
s.half:update(current_time_ms)
|
|
end
|
|
end
|
|
end
|
|
|
|
function PetalFever:draw_stream(i, opacity, scale)
|
|
local stream, s = self.spec.streams[i], self.streams[i]
|
|
-- pass 0 is in the first half of its flight, pass 1 (once there is one) in the second
|
|
for pass = 0, math.min(s.laps, 1) do
|
|
local p = (pass * 1000 + s.half.attribute) / 2000
|
|
local fade = opacity * (stream.alpha or 1)
|
|
if stream.fade_out and p > 0.5 then fade = fade * (1 - p) * 2 end
|
|
local origin = stream.rotation and stream.half * scale or 0
|
|
for t = 0, TILES - 1 do
|
|
tex.draw_texture(self._ids[i], {
|
|
index = (stream.first or 0) + t,
|
|
x = math.floor(stream.dx * p * scale) + origin,
|
|
y = math.floor(stream.dy * p * scale) + origin,
|
|
fade = fade,
|
|
blend = stream.blend,
|
|
rotation = stream.rotation,
|
|
origin = stream.rotation and { origin, origin } or nil,
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
function PetalFever:draw()
|
|
local haze = env_value(self.haze) / 1000
|
|
if haze > 0 then tex.draw_texture(self._id_haze, { fade = haze, blend = self.spec.haze.blend }) end
|
|
local petals = env_value(self.petals) / 1000
|
|
if petals <= 0 then return end
|
|
local scale = tex.get_screen_scale()
|
|
for i in ipairs(self.spec.streams) do
|
|
if self.streams[i] then self:draw_stream(i, petals, scale) end
|
|
end
|
|
end
|
|
|
|
function PetalFever:destroy()
|
|
tex.unload_folder(self.spec.path, "bg_fever/" .. self.name)
|
|
end
|
|
|
|
return PetalFever
|