Files
YataiDONNijiiro/Scripts/game/dan_between.lua
T

99 lines
4.1 KiB
Lua

-- Dan course song intro: the fusuma (sliding doors) close over the lane, the song title and
-- subtitle fade in on them, then the doors open on the first chart.
-- The engine owns the timing and the door sounds (DanBetween in dan_between.h); this draws the frame
-- for `elapsed` ms after the intro began.
DanBetween = {}
DanBetween.__index = DanBetween
-- clip frames (60 fps): the clip starts at F_START, the text fades in at F_TEXT, the doors reopen at
-- F_OPEN and the clip ends at F_END
local FPS, F_START, F_TEXT, F_OPEN, F_END = 60.0, 2.0, 120.0, 201.0, 366.0
local TITLE = { x = 1209, y = 93, font_size = 54, outline = 4.0 }
local SUB = { x = 1209, y = 172, font_size = 30, outline = 3.0 }
local WHITE, BLACK = { 255, 255, 255, 255 }, { 0, 0, 0, 255 }
function DanBetween.new()
return setmetatable({}, DanBetween)
end
function DanBetween:start(title, subtitle, show_subtitle)
self.title_text, self.subtitle_text = nil, nil
if title ~= "" then
self.title_text = text.create_raw_text(title, TITLE.font_size > 0 and TITLE.font_size or 54,
WHITE, BLACK, false, TITLE.outline)
end
if show_subtitle and subtitle ~= "" then
self.subtitle_text = text.create_raw_text(subtitle, SUB.font_size > 0 and SUB.font_size or 30,
WHITE, BLACK, false, SUB.outline)
end
end
local function lerp(a, b, t) return a + (b - a) * t end
-- door position (fraction of the 480-wide half) at clip frame f
local function door_tx(f)
local px
if f <= 2.0 then px = 714.0
elseif f < 3.0 then px = lerp(714.0, 588.2, f - 2.0)
elseif f < 19.0 then
local k = (f - 3.0) / 16.0
px = lerp(588.2, 291.4, 1.0 - (math.exp(-3.0 * k) - math.exp(-3.0)) / (1.0 - math.exp(-3.0)))
elseif f < 51.0 then px = lerp(291.4, 272.5, (f - 19.0) / 32.0)
elseif f < 64.0 then px = lerp(272.5, 240.0, (f - 51.0) / 13.0)
elseif f <= F_OPEN then px = 240.0
elseif f < F_OPEN + 15.0 then
local k = (f - F_OPEN) / 15.0
px = lerp(240.0, 714.0, k * (2.0 - k))
else px = 714.0 end
return px / 480.0
end
local function text_alpha(f)
if f < F_TEXT then return 0.0 end
if f < 337.0 then return 1.0 end
return math.max(0.0, math.min(1.0, (365.0 - f) / 28.0))
end
function DanBetween:draw(lane_y, elapsed)
local f = F_START + elapsed * FPS / 1000.0
if f >= F_END then return end
local door_info = tex.get_texture_info("lane", "dan_between_fusuma")
local door = tex.get_texture("game/lane/dan_between_fusuma")
if not door_info or not door then return end
local a = text_alpha(f)
if a > 0.0 then
if self.title_text then
self.title_text:draw({ x = TITLE.x - self.title_text.width / 2.0,
y = TITLE.y - self.title_text.height / 2.0 + lane_y, fade = a })
end
if self.subtitle_text then
self.subtitle_text:draw({ x = SUB.x - self.subtitle_text.width / 2.0,
y = SUB.y - self.subtitle_text.height / 2.0 + lane_y, fade = a })
end
end
local mask_x, mask_y, mask_h = 498.0, 12.0, 195.0
local fill = tex.get_texture_info("lane", "dan_between_fill")
if fill then mask_x, mask_y, mask_h = fill.x[1], fill.y[1], fill.y2[1] end
tex.begin_scissor(mask_x, 0, tex.get_screen_width() - mask_x, tex.get_screen_height())
local door_y, door_h = door_info.y[1], door_info.y2[1]
local crop_top = math.max(0.0, mask_y - door_y)
local crop_h = math.max(0.0, math.min(door_h - crop_top, (mask_y + mask_h) - (door_y + crop_top)))
local sc = (door_info.height > 0 and door_h > 0) and door_h / door_info.height or 1.0
local src_top, src_h = crop_top / sc, crop_h / sc
local tx = door_tx(f) * door_info.x2[1]
tex.draw_texture(door, { x = tx, y = lane_y + crop_top, y2 = crop_h - door_h,
src = { x = 0, y = src_top, width = door_info.width, height = src_h } })
tex.draw_texture(door, { x = -tx, y = lane_y + crop_top, y2 = crop_h - door_h,
src = { x = 0, y = src_top, width = -door_info.width, height = src_h } })
tex.end_scissor()
end