Files
YataiDONNijiiro/Scripts/background/bg_objects/bg_anim.lua
T
TaikoZhongandClaude Fable 5.1 3e6783f8fb Lower backdrops: replay every element of the original movies
The five normal and three cleared backdrops were flat plates plus a few hand
rebuilt effects, so the koi, the treasure ships, the lantern glow and the
festival stalls never moved as they do in the original. Each movie is now
exported per shape instance with its own loop (bg_data/bg_anim/<name>.lua,
textures under background/bga_<name>) and replayed by bg_objects/bg_anim.lua at
60 fps on the lower half of the screen. bg_normal.lua and bg_fever.lua use it
when the data exists and keep their old drawing as the fallback; the cleared
backdrop's rise/fall wipe is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 12:28:29 +08:00

96 lines
3.0 KiB
Lua

-- Generic replay of an exported cabinet backdrop movie (lower half of the screen).
--
-- Data: Scripts/background/bg_data/bg_anim/<name>.lua (generated by
-- scratchpad/lyric/movie_export.py): `shapes[c] = {w, h, ox, oy}` and `normal`, a
-- list of shape instances in depth order, each with the period of its own loop and
-- channels tx/ty/sx/sy/rot/a (one number when constant, else one value per frame;
-- a = 0 means not placed) plus an optional presence mask `on`/`on_period`.
-- Textures: Graphics/background/bga_<name>/s<c>.png. The stage is 1920x540 and is
-- drawn at screen y 540; the same schema as the donbg band player.
local BGAnim = {}
BGAnim.__index = BGAnim
local FRAME_MS = 1000.0 / 60.0
local STAGE_Y = 540
local ONE = string.byte("1")
function BGAnim.available(name)
local ok, data = pcall(require, "background/bg_data/bg_anim/" .. name)
return ok and type(data) == "table" and data.normal ~= nil
end
function BGAnim.new(name, path)
local ok, data = pcall(require, "background/bg_data/bg_anim/" .. name)
if not ok or type(data) ~= "table" or not data.normal then return nil end
local self = setmetatable({}, BGAnim)
self.name = name
self.subset = "bga_" .. name
self.path = path or "background"
tex.load_folder(self.path, self.subset)
self.data = data
self.ids = {}
self.elapsed = 0
self.last_ms = nil
return self
end
function BGAnim:id_of(shape)
local id = self.ids[shape]
if id == nil then
id = tex.get_id(self.subset, "s" .. shape) or false
self.ids[shape] = id
end
return id or nil
end
function BGAnim:update(current_ms)
if self.last_ms then
local dt = current_ms - self.last_ms
if dt > 0 and dt < 500 then self.elapsed = self.elapsed + dt end
end
self.last_ms = current_ms
end
local function ch(v, i)
if type(v) == "number" then return v end
return v[i]
end
function BGAnim:draw(fade)
fade = fade or 1.0
if fade <= 0.002 then return end
local frame = math.floor(self.elapsed / FRAME_MS)
local list = self.data.normal
local shapes = self.data.shapes
for k = 1, #list do
local e = list[k]
local i = (frame % e.period) + 1
local a = ch(e.a, i)
if a > 0.002 and e.on then
if e.on:byte((frame % e.on_period) + 1) ~= ONE then a = 0 end
end
if a > 0.002 then
local s = shapes[e.shape]
local id = s and self:id_of(e.shape)
if id then
local sx, sy = ch(e.sx, i), ch(e.sy, i)
tex.draw_texture(id, {
x = ch(e.tx, i),
y = STAGE_Y + ch(e.ty, i),
x2 = s[1] * (sx - 1),
y2 = s[2] * (sy - 1),
origin = { s[3] * sx, s[4] * sy },
rotation = ch(e.rot, i),
fade = a * fade,
})
end
end
end
end
function BGAnim:destroy()
tex.unload_folder(self.path, self.subset)
end
return BGAnim