diff --git a/scripts/titlescreen.lua b/scripts/titlescreen.lua index c2d8a73..c8704d6 100644 --- a/scripts/titlescreen.lua +++ b/scripts/titlescreen.lua @@ -10,10 +10,6 @@ local SplashPage = require('titlescreen.splash') local ModeSelectPage = require("titlescreen.pages.modeselect.modeselectpage") local ServiceMenuPage = require("titlescreen.pages.service.mainmenupage") -local TitleScreen = require('titlescreen.title') -local ModeSelectScreen = require('titlescreen.modeselect') -local ServiceScreen = require('titlescreen.service') - game.Log("HELLO FROM TITLESCREEN", game.LOGGER_DEBUG) local screens = { [BootPage.__name] = BootPage.new(), @@ -84,7 +80,7 @@ local function handleKnobs() if math.abs(knobProgress[1]) > knobThreshold then if pageView:get() then - pageView:get():handleKnobInput(game.KNOB_LEFT, knobProgress[1]) + pageView:get():handleKnobInput(game.KNOB_LEFT, knobProgress[1]) end end diff --git a/scripts/titlescreen/pages/splash/creditspage.lua b/scripts/titlescreen/pages/splash/creditspage.lua new file mode 100644 index 0000000..585a0b8 --- /dev/null +++ b/scripts/titlescreen/pages/splash/creditspage.lua @@ -0,0 +1,19 @@ +require "common.globals" +require "common.class" + +local Page = require "api.page.page" + +---@class CreditsPage : Page +local CreditsPage = { + +} + +---Create a new CreditsPage instance +---@param params? CreditsPage +function CreditsPage.new(params) + local self = CreateInstance(CreditsPage, params, Page) + + return self +end + +return CreditsPage \ No newline at end of file diff --git a/scripts/titlescreen/pages/splash/kshootmaniapage.lua b/scripts/titlescreen/pages/splash/kshootmaniapage.lua new file mode 100644 index 0000000..b7579de --- /dev/null +++ b/scripts/titlescreen/pages/splash/kshootmaniapage.lua @@ -0,0 +1,64 @@ +require "common.globals" +require "common.class" + +local Page = require "api.page.page" + +local splash1BgColor = {182, 0, 20} +local splash1Logo = gfx.CreateSkinImage("titlescreen/splash/ksm.png", 0) +local splash1LogoWidth, splash1LogoHeight = gfx.ImageSize(splash1Logo) + +local function splash1(deltaTime) + local splash1LogoXOffset = (Dim.design.width - splash1LogoWidth) / 2 + local splash1LogoYOffset = (Dim.design.height - splash1LogoHeight) / 2 + + calcFade(splash1Duration) + + gfx.BeginPath() + gfx.Rect(0, 0, Dim.design.width, Dim.design.height) + gfx.FillColor(splash1BgColor[1], splash1BgColor[2], splash1BgColor[3], fadeAlpha) + gfx.Fill() + + gfx.BeginPath() + gfx.ImageRect(splash1LogoXOffset, splash1LogoYOffset, splash1LogoWidth, splash1LogoHeight, splash1Logo, fadeAlpha / 255, 0) + + gfx.BeginPath() + gfx.LoadSkinFont("segoeui.ttf") + gfx.FillColor(255, 255, 255, fadeAlpha) + gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_BOTTOM) + gfx.FontSize(28) + + gfx.Text("Press START to skip...", 10, Dim.design.height - 10) + + if (splashTimer < 0) then + splashState = "splash2" + splash1SfxPlayed = false + splashTimer = 0 + return + end + + if splashTimer == 0 then + splashTimer = splash1Duration + end + + if not splash1SfxPlayed then + game.PlaySample("titlescreen/splash/splash1.wav") + splash1SfxPlayed = true + end + + splashTimer = splashTimer - deltaTime +end + +---@class KShootManiaPage : Page +local KShootManiaPage = { + +} + +---Create a new KShootManiaPage instance +---@param params? KShootManiaPage +function KShootManiaPage.new(params) + local self = CreateInstance(KShootManiaPage, params, Page) + + return self +end + +return KShootManiaPage \ No newline at end of file diff --git a/scripts/titlescreen/pages/splash/teamexceedpage.lua b/scripts/titlescreen/pages/splash/teamexceedpage.lua new file mode 100644 index 0000000..9484653 --- /dev/null +++ b/scripts/titlescreen/pages/splash/teamexceedpage.lua @@ -0,0 +1,58 @@ +require "common.globals" +require "common.class" + +local Page = require "api.page.page" + +local splash3BgColor = {255, 255, 255} +local splash3Logo = gfx.CreateSkinImage("titlescreen/splash/team-exceed.png", 0) +local splash3LogoWidth, splash3LogoHeight = gfx.ImageSize(splash3Logo) + +local function splash3(deltaTime) + local splash3LogoXOffset = (Dim.design.width - splash3LogoWidth) / 2 + local splash3LogoYOffset = (Dim.design.height - splash3LogoHeight) / 2 + + calcFade(splash3Duration) + + gfx.BeginPath() + gfx.Rect(0, 0, Dim.design.width, Dim.design.height) + gfx.FillColor(splash3BgColor[1], splash3BgColor[2], splash3BgColor[3], fadeAlpha) + gfx.Fill() + + gfx.BeginPath() + gfx.ImageRect(splash3LogoXOffset, splash3LogoYOffset, splash3LogoWidth, splash3LogoHeight, splash3Logo, fadeAlpha / 255, 0) + + gfx.BeginPath() + gfx.LoadSkinFont("segoeui.ttf") + gfx.FillColor(0, 0, 0, fadeAlpha) + gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_BOTTOM) + gfx.FontSize(28) + + gfx.Text("Press START to skip...", 10, Dim.design.height - 10) + + if (splashTimer < 0) then + splashState = "done" + splashTimer = 0 + return + end + + if splashTimer == 0 then + splashTimer = splash3Duration + end + + splashTimer = splashTimer - deltaTime +end + +---@class TeamExceedPage : Page +local TeamExceedPage = { + +} + +---Create a new TeamExceedPage instance +---@param params? TeamExceedPage +function TeamExceedPage.new(params) + local self = CreateInstance(TeamExceedPage, params, Page) + + return self +end + +return TeamExceedPage \ No newline at end of file diff --git a/scripts/titlescreen/pages/splash/uscpage.lua b/scripts/titlescreen/pages/splash/uscpage.lua new file mode 100644 index 0000000..58f80a7 --- /dev/null +++ b/scripts/titlescreen/pages/splash/uscpage.lua @@ -0,0 +1,58 @@ +require "common.globals" +require "common.class" + +local Page = require "api.page.page" + +local splash2BgColor = {255, 255, 255} +local splash2Logo = gfx.CreateSkinImage("titlescreen/splash/usc2.png", 0) +local splash2LogoWidth, splash2LogoHeight = gfx.ImageSize(splash2Logo) + +local function splash2(deltaTime) + local splash2LogoXOffset = (Dim.design.width - splash2LogoWidth) / 2 + local splash2LogoYOffset = (Dim.design.height - splash2LogoHeight) / 2 + + calcFade(splash2Duration) + + gfx.BeginPath() + gfx.Rect(0, 0, Dim.design.width, Dim.design.height) + gfx.FillColor(splash2BgColor[1], splash2BgColor[2], splash2BgColor[3], fadeAlpha) + gfx.Fill() + + gfx.BeginPath() + gfx.ImageRect(splash2LogoXOffset, splash2LogoYOffset, splash2LogoWidth, splash2LogoHeight, splash2Logo, fadeAlpha / 255, 0) + + gfx.BeginPath() + gfx.LoadSkinFont("segoeui.ttf") + gfx.FillColor(0, 0, 0, fadeAlpha) + gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_BOTTOM) + gfx.FontSize(28) + + gfx.Text("Press START to skip...", 10, Dim.design.height - 10) + + if (splashTimer < 0) then + splashState = "splash3" + splashTimer = 0 + return + end + + if splashTimer == 0 then + splashTimer = splash2Duration + end + + splashTimer = splashTimer - deltaTime +end + +---@class USCPage : Page +local USCPage = { + +} + +---Create a new USCPage instance +---@param params? USCPage +function USCPage.new(params) + local self = CreateInstance(USCPage, params, Page) + + return self +end + +return USCPage \ No newline at end of file diff --git a/scripts/titlescreen/splash.lua b/scripts/titlescreen/splash.lua index 7af04ff..ad279df 100644 --- a/scripts/titlescreen/splash.lua +++ b/scripts/titlescreen/splash.lua @@ -1,226 +1,126 @@ local Common = require("common.util") local Dim = require("common.dimensions") -local Wallpaper = require("components.wallpaper") -local Easing = require("common.easing") -local splash1BgColor = {182, 0, 20} -local splash1Logo = gfx.CreateSkinImage("titlescreen/splash/ksm.png", 0) -local splash1LogoWidth, splash1LogoHeight = gfx.ImageSize(splash1Logo) +local splashSample = "titlescreen/splash/splash1.wav" -local splash2BgColor = {255, 255, 255} -local splash2Logo = gfx.CreateSkinImage("titlescreen/splash/usc2.png", 0) -local splash2LogoWidth, splash2LogoHeight = gfx.ImageSize(splash2Logo) - -local splash3BgColor = {255, 255, 255} -local splash3Logo = gfx.CreateSkinImage("titlescreen/splash/team-exceed.png", 0) -local splash3LogoWidth, splash3LogoHeight = gfx.ImageSize(splash3Logo) - -local splashState = "init" -local splashTimer = 0 -local fadeDuration = 0.5 -local fadeAlpha = 0 -local splashInitDuration = 1 -local splash1Duration = 4 -local splash2Duration = 4 -local splash3Duration = 4 - -game.LoadSkinSample("titlescreen/splash/splash1.wav") +game.LoadSkinSample(splashSample) local splash1SfxPlayed = false -local triggerSkip = false +require "common.globals" +require "common.class" +local Page = require "api.page.page" +local KShootManiaPage = require "titlescreen.pages.splash.kshootmaniapage" +local USCPage = require "titlescreen.pages.splash.uscpage" +local TeamExceedPage = require "titlescreen.pages.splash.teamexceedpage" +local CreditsPage = require "titlescreen.pages.splash.creditspage" -local function calcFade(splashDuration) - local t = splashDuration - splashTimer - if t < fadeDuration then - fadeAlpha = Easing.linear(t, 0, 255, fadeDuration) -- fade in - elseif splashTimer < fadeDuration then - fadeAlpha = Easing.linear(splashTimer, 0, 255, fadeDuration) -- fade out - else - --fadeAlpha = 255 +---@class SplashPage : Page +---@field pages Page[] +---@field currentPage integer +---@field _isTransitioning boolean # actively fading between pages +local SplashPage = { + __name = "SplashScreen", + BACKGROUND_COLOR = {255, 255, 255}, + FADE_DURATION = 0.5 +} + +---Create a new SplashScreen instance +---@param params? SplashPage +---@return SplashPage +function SplashPage.new(params) + local self = CreateInstance(SplashPage, params, Page) + + self.currentPage = 1 + self.content = { + KShootManiaPage.new(), + USCPage.new(), + TeamExceedPage.new(), + CreditsPage.new() + } + + self._isTransitioning = false + + -- set callbacks + for index, page in ipairs(self.content) do + if index < #self.content then + page.onInvalidation = function (page_inst) + self._isTransitioning = true + self.currentPage = index + 1 + end + else -- last index + page.onInvalidation = function (page_inst) + self:onInvalidation() + end + end end - fadeAlpha = Common.round(Common.clamp(fadeAlpha, 0, 255)) + return self end -local function initSplash(deltaTime) - if (splashTimer < 0) then - splashState = "splash1" - splashTimer = 0 - return - end - - if splashTimer == 0 then - splashTimer = splashInitDuration - end - - splashTimer = splashTimer - deltaTime +function SplashPage:init() + self.currentPage = 1 + self._isTransitioning = false + Page.init(self) end -local function splash1(deltaTime) - local splash1LogoXOffset = (Dim.design.width - splash1LogoWidth) / 2 - local splash1LogoYOffset = (Dim.design.height - splash1LogoHeight) / 2 - - calcFade(splash1Duration) - - gfx.BeginPath() - gfx.Rect(0, 0, Dim.design.width, Dim.design.height) - gfx.FillColor(splash1BgColor[1], splash1BgColor[2], splash1BgColor[3], fadeAlpha) - gfx.Fill() - - gfx.BeginPath() - gfx.ImageRect(splash1LogoXOffset, splash1LogoYOffset, splash1LogoWidth, splash1LogoHeight, splash1Logo, fadeAlpha / 255, 0) - - gfx.BeginPath() - gfx.LoadSkinFont("segoeui.ttf") - gfx.FillColor(255, 255, 255, fadeAlpha) - gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_BOTTOM) - gfx.FontSize(28) - - gfx.Text("Press START to skip...", 10, Dim.design.height - 10) - - if (splashTimer < 0) then - splashState = "splash2" - splash1SfxPlayed = false - splashTimer = 0 - return - end - - if splashTimer == 0 then - splashTimer = splash1Duration - end - - if not splash1SfxPlayed then - game.PlaySample("titlescreen/splash/splash1.wav") - splash1SfxPlayed = true - end - - splashTimer = splashTimer - deltaTime -end - -local function splash2(deltaTime) - local splash2LogoXOffset = (Dim.design.width - splash2LogoWidth) / 2 - local splash2LogoYOffset = (Dim.design.height - splash2LogoHeight) / 2 - - calcFade(splash2Duration) - - gfx.BeginPath() - gfx.Rect(0, 0, Dim.design.width, Dim.design.height) - gfx.FillColor(splash2BgColor[1], splash2BgColor[2], splash2BgColor[3], fadeAlpha) - gfx.Fill() - - gfx.BeginPath() - gfx.ImageRect(splash2LogoXOffset, splash2LogoYOffset, splash2LogoWidth, splash2LogoHeight, splash2Logo, fadeAlpha / 255, 0) - - gfx.BeginPath() - gfx.LoadSkinFont("segoeui.ttf") - gfx.FillColor(0, 0, 0, fadeAlpha) - gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_BOTTOM) - gfx.FontSize(28) - - gfx.Text("Press START to skip...", 10, Dim.design.height - 10) - - if (splashTimer < 0) then - splashState = "splash3" - splashTimer = 0 - return - end - - if splashTimer == 0 then - splashTimer = splash2Duration - end - - splashTimer = splashTimer - deltaTime -end - -local function splash3(deltaTime) - local splash3LogoXOffset = (Dim.design.width - splash3LogoWidth) / 2 - local splash3LogoYOffset = (Dim.design.height - splash3LogoHeight) / 2 - - calcFade(splash3Duration) - - gfx.BeginPath() - gfx.Rect(0, 0, Dim.design.width, Dim.design.height) - gfx.FillColor(splash3BgColor[1], splash3BgColor[2], splash3BgColor[3], fadeAlpha) - gfx.Fill() - - gfx.BeginPath() - gfx.ImageRect(splash3LogoXOffset, splash3LogoYOffset, splash3LogoWidth, splash3LogoHeight, splash3Logo, fadeAlpha / 255, 0) - - gfx.BeginPath() - gfx.LoadSkinFont("segoeui.ttf") - gfx.FillColor(0, 0, 0, fadeAlpha) - gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_BOTTOM) - gfx.FontSize(28) - - gfx.Text("Press START to skip...", 10, Dim.design.height - 10) - - if (splashTimer < 0) then - splashState = "done" - splashTimer = 0 - return - end - - if splashTimer == 0 then - splashTimer = splash3Duration - end - - splashTimer = splashTimer - deltaTime -end - -local function reset() - triggerSkip = false - splashState = "init" - splashTimer = 0 - splash1SfxPlayed = false -end - -function render(deltaTime) - if triggerSkip then - reset() - game.StopSample("titlescreen/splash/splash1.wav") - return { - eventType = "switch", - toScreen = "title" - } - end - - Dim.updateResolution() - - Wallpaper.render() - - Dim.transformToScreenSpace() - - gfx.BeginPath() - gfx.Rect(0, 0, Dim.design.width, Dim.design.height) - gfx.FillColor(255, 255, 255) - gfx.Fill() - - if splashState == "init" then - initSplash(deltaTime) - elseif splashState == "splash1" then - splash1(deltaTime) - elseif splashState == "splash2" then - splash2(deltaTime) - elseif splashState == "splash3" then - splash3(deltaTime) - elseif splashState == "done" then - reset() - return { - eventType = "switch", - toScreen = "title" - } - else - game.Log("Splash screen state error, splashState: " .. splashState, game.LOGGER_ERROR) - splashState = "done" - end -end - -local function onButtonPressed(button) +function SplashPage:handleButtonInput(button) if button == game.BUTTON_STA then - triggerSkip = true + game.StopSample(splashSample) + self:onInvalidation() end end -return { - render = render, - onButtonPressed = onButtonPressed -} \ No newline at end of file +---Fade between pages +---@param fadeDuration? number +---@param fadeColor? integer[] +function SplashPage:fadeTransition(deltaTime, fadeDuration, fadeColor) + fadeDuration = fadeDuration or 0.5 + fadeColor = fadeColor or {255, 255, 255} + + local fadeAlpha = 0.0 + + -- reset variables on first call + if not self["__fadeStarted"] then + self.__fadeTimer = 0.0 + self.__fadeStarted = true + end + + local halfDuration = fadeDuration / 2 + if self.__fadeTimer < halfDuration then + fadeAlpha = Common.lerp(self.__fadeTimer, 0, 0, halfDuration, 255) -- fade out + elseif self.__fadeTimer - fadeDuration < 0 then + fadeAlpha = Common.lerp(self.__fadeTimer, halfDuration, 255, fadeDuration, 0) -- fade in + else + self.__fadeStarted = false -- fade done, reset variable + self._isTransitioning = false + end + + local fillColor = {table.unpack(fadeColor, 1, 3)} -- copy color table + table.insert(fillColor, fadeAlpha) -- add alpha + + gfx.BeginPath() + gfx.FillColor(table.unpack(fillColor)) + gfx.Rect(0, 0, Dim.design.width, Dim.design.height) + gfx.Fill() + + self.__fadeTimer = self.__fadeTimer + deltaTime +end + +function SplashPage:drawBackground(deltaTime) + gfx.BeginPath() + gfx.FillColor(table.unpack(self.BACKGROUND_COLOR)) + gfx.Rect(0, 0, Dim.design.width, Dim.design.height) + gfx.Fill() +end + +function SplashPage:drawContent(deltaTime) + self.content[self.currentPage]:render(deltaTime) +end + +function SplashPage:drawForeground(deltaTime) + local fadeColor = {255, 255, 255} + if self._isTransitioning then + self:fadeTransition(deltaTime, self.FADE_DURATION, fadeColor) + end +end + +return SplashPage