introduced PageManager

which made it pretty to get page instances (ewww '.__name')
from now page implementations use the PageManager to get page instances
SplashPage fading improvements
TitlePage implementation
replace viewHandler calls from page implementations with 'self:onInvalidation()'
fixed ListField focus implementation
fixed SelfTestField crash
MainMenuPage and subpages implementation
This commit is contained in:
Hersi 2022-06-29 00:35:52 +02:00
parent a6a95cbd9c
commit 6749cb2a1c
28 changed files with 585 additions and 357 deletions

View File

@ -0,0 +1,60 @@
require "common.globals"
require "common.class"
---@type PageManager
local instance = nil
---@class PageManager
---@field pages Page[]
local PageManager = {
__name = "PageManager"
}
---Create new PageManager instance
---@param params? PageManager
---@return PageManager
function PageManager.new(params)
params = params or {}
local self = CreateInstance(PageManager, params)
self.pages = params.pages or {}
return self
end
---Get PageManager instance
---@return PageManager
function PageManager.get()
if not instance then
instance = PageManager.new()
end
return instance
end
---Store page with default name
---@param page Page
function PageManager:storePage(page)
if self.pages[page.__name] then
game.Log(self.__name .. ":storePage() : page `" .. tostring(page) .. "` already stored, overwriting...", game.LOGGER_WARNING)
else
game.Log(self.__name .. ":storePage() : stored page `" .. tostring(page) .. "` with key '" .. page.__name .. "'", game.LOGGER_DEBUG)
end
self.pages[page.__name] = page
end
---Get page by name or by class (default name)
---@param page string|Page
function PageManager:getPage(page)
if type(page) == "string" then
return self.pages[page]
elseif type(page) == "table" and page.__name then
return self.pages[page.__name]
end
game.Log(self.__name .. ":getPage() : invalid parameter (" .. tostring(page) .. ")", game.LOGGER_WARNING)
return nil
end
return PageManager

View File

@ -34,6 +34,11 @@ end
---Navigate to page
---@param page Page # page to put on top of the pageStack
function PageView:navigate(page)
if not page then
game.Log(self .. ":navigate() : page is nil, cannot navigate", game.LOGGER_ERROR)
return
end
page.viewHandler = self
pushStack(self.pageStack, page)
self:onNavigated(false)

View File

@ -1,26 +1,53 @@
require("common.globals")
local Common = require("common.util")
local Dim = require("common.dimensions")
local Wallpaper = require("components.wallpaper")
require "common.globals"
local Common = require "common.util"
local Dim = require "common.dimensions"
local Wallpaper = require "components.wallpaper"
local PageView = require("api.page.pageview")
local PageView = require "api.page.pageview"
local PageManager = require "api.page.pagemanager"
local BootPage = require("titlescreen.boot")
local SplashPage = require('titlescreen.splash')
local ModeSelectPage = require("titlescreen.pages.modeselect.modeselectpage")
local ServiceMenuPage = require("titlescreen.pages.service.mainmenupage")
local BootPage = require "titlescreen.boot"
local CheckUpdatePage = require "titlescreen.pages.boot.checkupdatepage"
game.Log("HELLO FROM TITLESCREEN", game.LOGGER_DEBUG)
local screens = {
[BootPage.__name] = BootPage.new(),
[SplashPage.__name] = SplashPage.new(),
--title = titleScreen,
--[tostring(ModeSelectPage)] = ModeSelectPage.new(),
--[tostring(ServiceMenuPage)] = ServiceMenuPage.new()
}
local SplashPage = require "titlescreen.splash"
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 TitlePage = require "titlescreen.title"
local MainMenuPage = require "titlescreen.mainmenu"
local ServiceMenuPage = require "titlescreen.service"
local InputCheckPage = require "titlescreen.components.inputbuttonfield"
local ScreenCheckPage = require "titlescreen.pages.service.screencheckpage"
local ColorCheckPage = require "titlescreen.pages.service.colorcheckpage"
local VersionInfoPage = require "titlescreen.pages.service.versioninfopage"
local pageView = PageView.new()
local pageManager = PageManager.get()
pageManager:storePage(CheckUpdatePage.new())
pageManager:storePage(BootPage.new())
pageManager:storePage(KShootManiaPage.new())
pageManager:storePage(USCPage.new())
pageManager:storePage(TeamExceedPage.new())
pageManager:storePage(CreditsPage.new())
pageManager:storePage(SplashPage.new())
pageManager:storePage(TitlePage.new())
pageManager:storePage(MainMenuPage.new())
pageManager:storePage(InputCheckPage.new())
pageManager:storePage(ScreenCheckPage.new())
pageManager:storePage(ColorCheckPage.new())
pageManager:storePage(VersionInfoPage.new())
pageManager:storePage(ServiceMenuPage.new())
pageView.onNavigated = function(self, back)
game.Log(tostring(self) .. " navigated " .. (back and "back " or "") .. "to: " .. tostring(pageView:get()),
game.LOGGER_INFO
@ -31,34 +58,42 @@ pageView.onEmptied = function(self)
game.Log(tostring(self) .. " empty!", game.LOGGER_WARNING)
end
local function switchScreens(newScreen)
pageView:replace(newScreen)
local pages = PageManager.get().pages
pageManager:getPage(BootPage).onInvalidation = function(self, toVersionPage)
if toVersionPage then
pageView:replace(pageManager:getPage(ServiceMenuPage))
pageView:get():init()
pageView:navigate(pageManager:getPage(VersionInfoPage))
pageView:get():init()
else
pageView:replace(pageManager:getPage(SplashPage))
pageView:get():init()
end
end
pageManager:getPage(SplashPage).onInvalidation = function(self)
pageView:replace(pageManager:getPage(TitlePage))
pageView:get():init()
end
screens[BootPage.__name].onInvalidation = function(self)
switchScreens(screens[SplashPage.__name])
pageManager:getPage(TitlePage).onInvalidation = function(self, toServiceMenu)
if toServiceMenu then
pageView:replace(pageManager:getPage(ServiceMenuPage))
pageView:get():init()
else
pageView:replace(pageManager:getPage(MainMenuPage))
pageView:get():init()
end
end
screens[SplashPage.__name].onInvalidation = function(self)
--TODO: TitlePage
--switchScreens(screens[TitlePage.__name])
pageManager:getPage(ServiceMenuPage).onInvalidation = function(self)
pageView:replace(pageManager:getPage(SplashPage))
pageView:get():init()
end
--[[ TODO: remaining Pages
screens[TitlePage.__name].onInvalidation = function(self)
switchScreens(screens[ModeSelectPage.__name])
end
screens[ServiceMenuPage.__name].onInvalidation = function(self)
switchScreens(screens[SplashPage.__name])
end
]]
--local currentScreen = game.GetSkinSetting("animations_skipIntro") and screens.title or screens.boot -- show boot screen if skipIntro is not set
switchScreens(screens[BootPage.__name])
pageView:replace(pages[BootPage.__name])
pageView:get():init()
local function deltaKnob(delta)
-- can someone tell me what the hell does this do? - Hersi

View File

@ -1,13 +1,17 @@
require("common.globals")
require("common.class")
require("common.filereader")
local Dim = require("common.dimensions")
local Version = require("common.version")
local Page = require("api.page.page")
local CheckUpdatePage = require("titlescreen.pages.boot.checkupdatepage")
local ServiceField = require("titlescreen.components.servicefield")
local ListField = require("titlescreen.components.listfield")
local SelfTestField = require("titlescreen.components.selftestfield")
require "common.globals"
require "common.class"
require "common.filereader"
local Dim = require "common.dimensions"
local Version = require "common.version"
local PageManager = require "api.page.pagemanager"
local Page = require "api.page.page"
local CheckUpdatePage = require "titlescreen.pages.boot.checkupdatepage"
local ServiceField = require "api.page.servicefield"
local ListField = require "titlescreen.components.listfield"
local SelfTestField = require "titlescreen.components.selftestfield"
---@class BootPage: Page
local BootPage = {
@ -22,8 +26,13 @@ function BootPage.new(params)
local self = CreateInstance(BootPage, params, Page)
local pageManager = PageManager.get()
self._networkResult = {}
pageManager:getPage(CheckUpdatePage).onInvalidation = function (page_self, reason)
self:onInvalidation(reason)
end
self:addField(ServiceField.new{posX = 32, posY = 32, label = Version.getLongVersion(), value = ""})
self:addField(ServiceField.new{posX = 64, posY = 64, label = "UNNAMED SDVX CLONE STARTUP...", value = ""})
@ -78,7 +87,8 @@ function BootPage.new(params)
IR.Heartbeat(function(res) self._networkResult = res end) -- IR doesn't like being called in a coroutine
elseif status == SelfTestStatus.PASS or status == SelfTestStatus.OK then
if self.viewHandler then
self.viewHandler:navigate(CheckUpdatePage.new())
self.viewHandler:navigate(pageManager:getPage(CheckUpdatePage))
self.viewHandler:get():init()
end
end
end

View File

@ -1,6 +1,6 @@
require("common.class")
local Util = require("common.util")
local ServiceField = require("titlescreen.components.servicefield")
local ServiceField = require("api.page.servicefield")
---@class CheckUpdateField: ServiceField
---@field onUpdateAvailable nil|fun(url: string, version: string)
@ -57,7 +57,7 @@ function CheckUpdateField:tick(deltaTime)
self.onUpdateAvailable(self._url, self._version)
self._onUpdateAvailableFired = true
else
self:getParentPage().viewHandler:clear() -- Exit out of bootscreen
self:getParentPage():onInvalidation() -- Exit out of bootscreen
end
end
end

View File

@ -1,6 +1,6 @@
require("common.class")
local Util = require("common.util")
local ServiceField = require("titlescreen.components.servicefield")
local ServiceField = require("api.page.servicefield")
---@class ColorGradientField: ServiceField
local ColorGradientField = {

View File

@ -1,5 +1,5 @@
require("common.class")
local ServiceField = require("titlescreen.components.servicefield")
local ServiceField = require("api.page.servicefield")
---@class InputButtonField: ServiceField
---@field button integer

View File

@ -1,6 +1,6 @@
require("common.class")
local Util = require("common.util")
local ServiceField = require("titlescreen.components.servicefield")
local ServiceField = require("api.page.servicefield")
---@class InputKnobField: ServiceField
---@field knob integer

View File

@ -1,6 +1,6 @@
require("common.class")
local ContainerField = require("api.page.containerfield")
local ServiceField = require("titlescreen.components.servicefield")
local ServiceField = require("api.page.servicefield")
---@class ListField: ContainerField, ServiceField
---@field selectedIndex integer
@ -34,7 +34,7 @@ end
---@param obj? any # message object for the field
function ListField:focus(obj)
if self._state == ServiceFieldState.ACTIVE then
if self.focused then
return
end
@ -62,6 +62,19 @@ function ListField:focus(obj)
ServiceField.focus(self)
end
function ListField:unfocus()
if not self.focused then
return
end
local field = self.content[self.selectedIndex]
if field and field.unfocus then
field:unfocus()
end
ServiceField.unfocus(self)
end
---Add field to list container
---@param field Field
function ListField:addField(field)
@ -100,16 +113,8 @@ function ListField:handleButtonInput(button)
return true
end
if button == game.BUTTON_BCK then
local viewHandler = self:getParentPage().viewHandler
if viewHandler then
viewHandler:back()
end
return true
end
if self.locked then
return true
return false
end
local direction = 0
@ -121,7 +126,7 @@ function ListField:handleButtonInput(button)
end
if direction ~= 0 then
field:deactivate()
field:unfocus()
self.selectedIndex = self.selectedIndex + direction
@ -131,9 +136,11 @@ function ListField:handleButtonInput(button)
field = self.content[self.selectedIndex]
field:focus()
return true
end
return true
return false
end
---@param deltaTime number # frametime in seconds

View File

@ -1,6 +1,6 @@
require("common.class")
local Util = require("common.util")
local ServiceField = require("titlescreen.components.servicefield")
local ServiceField = require("api.page.servicefield")
---@class SelfTestStatus
SelfTestStatus = {
@ -20,6 +20,7 @@ end
---@field checkTask nil|fun(): SelfTestStatus # a function that will run asynchronously on activating the Field
---@field status SelfTestStatus
---@field _thread thread
---@field _timer number
local SelfTestField = {
__name = "SelfTestField",
COLOR_INPROGRESS = {255, 255, 255, 255},
@ -39,6 +40,7 @@ function SelfTestField.new(params)
local self = CreateInstance(SelfTestField, params, ServiceField)
self._timer = 0.0
self._thread = nil
return self
@ -54,7 +56,7 @@ end
function SelfTestField:_closeThread()
if self._thread and coroutine.status(self._thread) ~= "dead" then
coroutine.close(self._thread)
--coroutine.close(self._thread) --only god knows why this crashes lmao
end
end
@ -89,6 +91,8 @@ end
function SelfTestField:tick(deltaTime)
self:_resumeThread()
self._timer = self._timer + deltaTime
end
---@param status SelfTestStatus

View File

@ -1,6 +1,6 @@
require("common.class")
local LinkField = require("api.page.linkfield")
local ServiceField = require("titlescreen.components.servicefield")
local ServiceField = require("api.page.servicefield")
---@class ServiceLinkField: LinkField, ServiceField
local ServiceLinkField = {

View File

@ -1,5 +1,5 @@
require("common.class")
local ServiceField = require("titlescreen.components.servicefield")
local ServiceField = require("api.page.servicefield")
---@class UpdateField: ServiceField
---@field _timer number

View File

@ -1,3 +1,5 @@
require "common.globals"
require "common.class"
local Footer = require("components.footer")
local Wallpaper = require("components.wallpaper")
@ -468,10 +470,50 @@ local function onMousePressed(button)
end
return {
render = render,
reset = reset,
onKnobsChange = onKnobsChange,
onButtonPressed = onButtonPressed,
onMousePressed = onMousePressed,
local Background = require "components.background"
local Animation = require "api.animation"
local AudioSample = require "api.audiosample"
local Page = require "api.page.page"
local Footer = require "components.footer"
local crew = game.GetSkinSetting("single_idol")
---@class MainMenuPage : Page
---@field _idolAnimationState AnimationState
local MainMenuPage = {
__name = "MainMenuPage",
anims = {
idolAnimation = Animation.new("crew/anim/" .. crew, {
fps = 30, loop = true,
centered = true, x = Dim.design.width / 2, y = Dim.design.height / 2,
width = Dim.design.width, height = Dim.design.height,
})
},
audiosamples = {
bgm = AudioSample.new{path = "titlescreen/bgm.wav", exclusive = true, loop = true},
}
}
function MainMenuPage.new(params)
local self = CreateInstance(MainMenuPage, params, Page)
return self
end
function MainMenuPage:init()
self._idolAnimationState = self.anims.idolAnimation:start()
self.audiosamples.bgm:play()
end
function MainMenuPage:drawBackground(deltaTime)
Background.draw(deltaTime)
self._idolAnimationState:render(deltaTime)
end
function MainMenuPage:drawForeground(deltaTime)
Footer.draw(deltaTime)
end
return MainMenuPage

View File

@ -50,14 +50,10 @@ function CheckUpdatePage.new(params)
end
if button == game.BUTTON_BCK then
self.viewHandler:clear() -- Cancel update, close screen
self:onInvalidation() -- Cancel update, close screen
return true
elseif button == game.BUTTON_STA then
-- NOTE: this is a huge ass hack, please rethink
local MainMenuPage = require("titlescreen.pages.service.mainmenupage")
local VersionInfoPage = require("titlescreen.pages.service.versioninfopage")
self.viewHandler:replace(MainMenuPage.new())
self.viewHandler:navigate(VersionInfoPage.new())
self:onInvalidation(true)
return true
end
@ -83,7 +79,7 @@ function CheckUpdatePage:handleButtonInput(button)
end
if button == game.BUTTON_BCK then
self.viewHandler:back()
self:onInvalidation()
end
end

View File

@ -1,18 +1,13 @@
require "common.class"
local Dim = require "common.dimensions"
local Lang = require "language.call"
local AudioSample = require "api.audiosample"
local Animation = require "api.animation"
local Page = require "api.page.page"
local Background = require "components.background"
local Footer = require "components.footer"
local Header = require "components.headers.modeSelectHeader"
local crew = game.GetSkinSetting("single_idol")
---@class ModeSelectPage: Page
---@field _idolAnimationState AnimationState
local ModeSelectPage = {
__name = "ModeSelectPage",
images = {
@ -23,14 +18,9 @@ local ModeSelectPage = {
selectedButtonOverImage = gfx.CreateSkinImage("titlescreen/selected_button_over.png", 0)
},
anims = {
idolAnimation = Animation.new("crew/anim/" .. crew, {
fps = 30, loop = true,
centered = true, x = Dim.design.width / 2, y = Dim.design.height / 2,
width = Dim.design.width, height = Dim.design.height,
})
},
audiosamples = {
bgm = AudioSample.new{path = "titlescreen/bgm.wav", exclusive = true, loop = true},
cursorChange = AudioSample.new{path = "titlescreen/cursor_change.wav"},
cursorSelect = AudioSample.new{path = "titlescreen/cursor_select.wav"}
},
@ -48,18 +38,11 @@ function ModeSelectPage.new(params)
end
function ModeSelectPage:init()
self._idolAnimationState = self.anims.idolAnimation:start()
self.audiosamples.bgm:play()
end
function ModeSelectPage:drawBackground(deltaTime)
Background.draw(deltaTime)
self._idolAnimationState:render(deltaTime)
end
function ModeSelectPage:drawForeground(deltaTime)
Header.draw()
Footer.draw(deltaTime)
end
return ModeSelectPage

View File

@ -0,0 +1,22 @@
require "common.class"
local Page = require "api.page.page"
local Header = require "components.headers.myRoomHeader"
---@class MyRoomPage: Page
---@field _idolAnimationState AnimationState
local MyRoomPage = {
__name = "MyRoomPage",
}
function MyRoomPage.new(params)
local self = CreateInstance(MyRoomPage, params, Page)
return self
end
function MyRoomPage:drawForeground(deltaTime)
Header.draw()
end
return MyRoomPage

View File

@ -1,5 +1,5 @@
require("common.class")
local ServicePage = require("titlescreen.pages.service.servicepage")
local ServicePage = require("api.page.servicepage")
local ListField = require("titlescreen.components.listfield")
local ColorGradientField = require("titlescreen.components.colorgradientfield")

View File

@ -1,5 +1,5 @@
require("common.class")
local ServicePage = require("titlescreen.pages.service.servicepage")
local ServicePage = require("api.page.servicepage")
local InputButtonField = require("titlescreen.components.inputbuttonfield")
local InputKnobField = require("titlescreen.components.inputknobfield")
local ListField = require("titlescreen.components.listfield")

View File

@ -1,38 +0,0 @@
require("common.class")
local ServicePage = require("titlescreen.pages.service.servicepage")
local InputCheckPage = require("titlescreen.pages.service.inputcheckpage")
local ScreenCheckPage = require("titlescreen.pages.service.screencheckpage")
local ColorCheckPage = require("titlescreen.pages.service.colorcheckpage")
local VersionInfoPage = require("titlescreen.pages.service.versioninfopage")
local ServiceLinkField = require("titlescreen.components.servicelinkfield")
local ListField = require("titlescreen.components.listfield")
---@class MainMenuPage: ServicePage
local MainMenuPage = {
__name = "MainMenuPage",
}
---Create a new MainMenuPage instance
---@param params? MainMenuPage # initial parameters
---@return MainMenuPage
function MainMenuPage.new(params)
params = params or {}
params.title = params.title or "MAIN MENU"
local self = CreateInstance(MainMenuPage, params, ServicePage)
local list = ListField.new()
list:addField(ServiceLinkField.new{label = "INPUT CHECK", link = InputCheckPage.new()})
list:addField(ServiceLinkField.new{label = "SCREEN CHECK", link = ScreenCheckPage.new()})
list:addField(ServiceLinkField.new{label = "COLOR CHECK", link = ColorCheckPage.new()})
list:addField(ServiceLinkField.new{label = "VERSION INFORMATION", link = VersionInfoPage.new()})
list:refreshFields()
self:addField(list)
self:refreshFields()
return self
end
return MainMenuPage

View File

@ -1,6 +1,6 @@
require("common.class")
local Dim = require("common.dimensions")
local ServicePage = require("titlescreen.pages.service.servicepage")
local ServicePage = require("api.page.servicepage")
---@class ScreenCheckPage: ServicePage
local ScreenCheckPage = {

View File

@ -2,8 +2,8 @@ require("common.class")
require("common.filereader")
require("common.gameconfig")
local Version = require("common.version")
local ServicePage = require("titlescreen.pages.service.servicepage")
local ServiceField = require("titlescreen.components.servicefield")
local ServicePage = require("api.page.servicepage")
local ServiceField = require("api.page.servicefield")
local UpdateField = require("titlescreen.components.updatefield")
local ListField = require("titlescreen.components.listfield")

View File

@ -1,11 +1,20 @@
require "common.globals"
require "common.class"
local Dim = require "common.dimensions"
local Image = require "api.image"
local Page = require "api.page.page"
---@class CreditsPage : Page
---@field logo_img Image
---@field _timer number
local CreditsPage = {
__name = "CreditsPage",
BACKGROUND_COLOR = {255, 255, 255},
LOGO_PATH = "",
TIMEOUT = 3.0
}
---Create a new CreditsPage instance
@ -13,7 +22,42 @@ local CreditsPage = {
function CreditsPage.new(params)
local self = CreateInstance(CreditsPage, params, Page)
self.logo_img = Image.new(self.LOGO_PATH)
self._timer = 0.0
return self
end
function CreditsPage:init()
self._timer = 0.0
Page.init(self)
end
function CreditsPage: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 CreditsPage:drawContent(deltaTime)
local x = (Dim.design.width - self.logo_img.width) / 2
local y = (Dim.design.height - self.logo_img.height) / 2
self.logo_img:setPosition(x, y)
self.logo_img:render()
end
function CreditsPage:render(deltaTime)
Page.render(self, deltaTime)
if self._timer > self.TIMEOUT then
self:onInvalidation()
end
self._timer = self._timer + deltaTime
end
return CreditsPage

View File

@ -1,56 +1,23 @@
require "common.globals"
require "common.class"
local Dim = require "common.dimensions"
local Image = require "api.image"
local AudioSample = require "api.audiosample"
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
---@field logo_img Image
---@field splash_sample AudioSample
---@field _timer number
---@field _sample_played boolean
local KShootManiaPage = {
__name = "KShootManiaPage",
BACKGROUND_COLOR = {182, 0, 20},
LOGO_PATH = "titlescreen/splash/ksm.png",
SAMPLE_PATH = "titlescreen/splash/splash1.wav",
TIMEOUT = 3.0
}
---Create a new KShootManiaPage instance
@ -58,7 +25,49 @@ local KShootManiaPage = {
function KShootManiaPage.new(params)
local self = CreateInstance(KShootManiaPage, params, Page)
self.logo_img = Image.new(self.LOGO_PATH)
self.splash_sample = AudioSample.new({path = self.SAMPLE_PATH})
self._timer = 0.0
self._sample_played = false
return self
end
function KShootManiaPage:init()
self._timer = 0.0
self._sample_played = false
Page.init(self)
end
function KShootManiaPage: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 KShootManiaPage:drawContent(deltaTime)
local x = (Dim.design.width - self.logo_img.width) / 2
local y = (Dim.design.height - self.logo_img.height) / 2
self.logo_img:setPosition(x, y)
self.logo_img:render()
end
function KShootManiaPage:render(deltaTime)
if not self._sample_played then
self.splash_sample:play()
end
Page.render(self, deltaTime)
if self._timer > self.TIMEOUT then
self:onInvalidation()
end
self._timer = self._timer + deltaTime
end
return KShootManiaPage

View File

@ -1,6 +1,10 @@
require "common.globals"
require "common.class"
local Dim = require "common.dimensions"
local Image = require "api.image"
local Page = require "api.page.page"
local splash3BgColor = {255, 255, 255}
@ -43,8 +47,13 @@ local function splash3(deltaTime)
end
---@class TeamExceedPage : Page
---@field logo_img Image
---@field _timer number
local TeamExceedPage = {
__name = "TeamExceedPage",
BACKGROUND_COLOR = {255, 255, 255},
LOGO_PATH = "titlescreen/splash/team-exceed.png",
TIMEOUT = 3.0
}
---Create a new TeamExceedPage instance
@ -52,7 +61,42 @@ local TeamExceedPage = {
function TeamExceedPage.new(params)
local self = CreateInstance(TeamExceedPage, params, Page)
self.logo_img = Image.new(self.LOGO_PATH)
self._timer = 0.0
return self
end
function TeamExceedPage:init()
self._timer = 0.0
Page.init(self)
end
function TeamExceedPage: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 TeamExceedPage:drawContent(deltaTime)
local x = (Dim.design.width - self.logo_img.width) / 2
local y = (Dim.design.height - self.logo_img.height) / 2
self.logo_img:setPosition(x, y)
self.logo_img:render()
end
function TeamExceedPage:render(deltaTime)
Page.render(self, deltaTime)
if self._timer > self.TIMEOUT then
self:onInvalidation()
end
self._timer = self._timer + deltaTime
end
return TeamExceedPage

View File

@ -1,50 +1,20 @@
require "common.globals"
require "common.class"
local Dim = require "common.dimensions"
local Image = require "api.image"
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
---@field logo_img Image
---@field _timer number
local USCPage = {
__name = "USCPage",
BACKGROUND_COLOR = {255, 255, 255},
LOGO_PATH = "titlescreen/splash/usc2.png",
TIMEOUT = 3.0
}
---Create a new USCPage instance
@ -52,7 +22,42 @@ local USCPage = {
function USCPage.new(params)
local self = CreateInstance(USCPage, params, Page)
self.logo_img = Image.new(self.LOGO_PATH)
self._timer = 0.0
return self
end
function USCPage:init()
self._timer = 0.0
Page.init(self)
end
function USCPage: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 USCPage:drawContent(deltaTime)
local x = (Dim.design.width - self.logo_img.width) / 2
local y = (Dim.design.height - self.logo_img.height) / 2
self.logo_img:setPosition(x, y)
self.logo_img:render()
end
function USCPage:render(deltaTime)
Page.render(self, deltaTime)
if self._timer > self.TIMEOUT then
self:onInvalidation()
end
self._timer = self._timer + deltaTime
end
return USCPage

View File

@ -1,60 +1,42 @@
local Dim = require("common.dimensions")
local Wallpaper = require("components.wallpaper")
require("common.class")
local PageView = require("api.page.pageview")
local MainMenuPage = require("titlescreen.pages.service.mainmenupage")
local PageManager = require "api.page.pagemanager"
--[[ WIP: REIMPLEMENTATION
local ServicePage = require("api.page.servicepage")
local InputCheckPage = require("titlescreen.pages.service.inputcheckpage")
local ScreenCheckPage = require("titlescreen.pages.service.screencheckpage")
local ColorCheckPage = require("titlescreen.pages.service.colorcheckpage")
local VersionInfoPage = require("titlescreen.pages.service.versioninfopage")
local ServiceLinkField = require("titlescreen.components.servicelinkfield")
local ListField = require("titlescreen.components.listfield")
local rootMenu = {
{label = "IDOLS", children = {{label = "GRACEv6"}, {label = "NEARNOAHv6"}, {label = "IDKv6"}}},
{
label = "LASER COLORS",
children = {
{
label = "LEFT LASER",
children = {
{label = "BLUE", color = {0, 128, 255}},
{label = "PINK", color = {255, 0, 255}},
{label = "GREEN", color = {0, 255, 0}},
{label = "YELLOW", color = {255, 255, 0}},
},
},
{
label = "RIGHT LASER",
children = {{label = "BLUE"}, {label = "PINK"}, {label = "GREEN"}, {label = "YELLOW"}},
},
},
},
---@class ServiceMenuPage: ServicePage
local ServiceMenuPage = {
__name = "ServiceMenuPage",
}
]]
---Create a new MainMenuPage instance
---@param params? MainMenuPage # initial parameters
---@return MainMenuPage
function ServiceMenuPage.new(params)
params = params or {}
local currentpage = MainMenuPage.new()
params.title = params.title or "MAIN MENU"
local pageview = PageView.new(currentpage)
local self = CreateInstance(ServiceMenuPage, params, ServicePage)
local function reset()
pageview = PageView.new(currentpage)
local pageManager = PageManager.get()
local list = ListField.new()
list:addField(ServiceLinkField.new{label = "INPUT CHECK", link = pageManager:getPage(InputCheckPage)})
list:addField(ServiceLinkField.new{label = "SCREEN CHECK", link = pageManager:getPage(ScreenCheckPage)})
list:addField(ServiceLinkField.new{label = "COLOR CHECK", link = pageManager:getPage(ColorCheckPage)})
list:addField(ServiceLinkField.new{label = "VERSION INFORMATION", link = pageManager:getPage(VersionInfoPage)})
list:refreshFields()
self:addField(list)
self:refreshFields()
return self
end
local function render(deltaTime)
Dim.updateResolution()
Wallpaper.render()
Dim.transformToScreenSpace()
pageview:render(deltaTime)
--pageview will be empty when you `back()` out of the root page
if not pageview:get() then
return {eventType = "switch", toScreen = "splash"}
end
end
local function onButtonPressed(button)
pageview:get():handleButtonInput(button)
end
return {reset = reset, render = render, onButtonPressed = onButtonPressed}
return ServiceMenuPage

View File

@ -1,13 +1,11 @@
local Common = require("common.util")
local Util = require("common.util")
local Dim = require("common.dimensions")
local splashSample = "titlescreen/splash/splash1.wav"
game.LoadSkinSample(splashSample)
local splash1SfxPlayed = false
require "common.globals"
require "common.class"
local PageManager = require "api.page.pagemanager"
local Page = require "api.page.page"
local KShootManiaPage = require "titlescreen.pages.splash.kshootmaniapage"
local USCPage = require "titlescreen.pages.splash.uscpage"
@ -18,10 +16,11 @@ local CreditsPage = require "titlescreen.pages.splash.creditspage"
---@field pages Page[]
---@field currentPage integer
---@field _isTransitioning boolean # actively fading between pages
---@field _isFadeOut boolean # fading out between pages
local SplashPage = {
__name = "SplashScreen",
BACKGROUND_COLOR = {255, 255, 255},
FADE_DURATION = 0.5
FADE_DURATION = 0.25
}
---Create a new SplashScreen instance
@ -30,22 +29,24 @@ local SplashPage = {
function SplashPage.new(params)
local self = CreateInstance(SplashPage, params, Page)
self.currentPage = 1
local pageManager = PageManager.get()
self.currentPage = 0 -- start on nil page
self.content = {
KShootManiaPage.new(),
USCPage.new(),
TeamExceedPage.new(),
CreditsPage.new()
pageManager:getPage(KShootManiaPage),
pageManager:getPage(USCPage),
pageManager:getPage(TeamExceedPage),
pageManager:getPage(CreditsPage),
}
self._isTransitioning = false
self._isTransitioning = true -- immediately transition to first page
self._isFadeOut = 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)
@ -57,26 +58,25 @@ function SplashPage.new(params)
end
function SplashPage:init()
self.currentPage = 1
self._isTransitioning = false
self.currentPage = 0
self._isTransitioning = true
for _, page in ipairs(self.content) do
page:init()
end
Page.init(self)
end
function SplashPage:handleButtonInput(button)
if button == game.BUTTON_STA then
game.StopSample(splashSample)
game.StopSample(KShootManiaPage.SAMPLE_PATH) -- hack to stop splash screen sample from playing when skipping
self:onInvalidation()
end
end
---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
function SplashPage:fadeTransition(deltaTime)
local fadeDuration = self.FADE_DURATION
local fadeColor = self.BACKGROUND_COLOR
-- reset variables on first call
if not self["__fadeStarted"] then
@ -84,14 +84,27 @@ function SplashPage:fadeTransition(deltaTime, fadeDuration, fadeColor)
self.__fadeStarted = true
end
local fadeAlpha = 0.0
local halfDuration = fadeDuration / 2
if self.__fadeTimer < halfDuration then
fadeAlpha = Common.lerp(self.__fadeTimer, 0, 0, halfDuration, 255) -- fade out
fadeAlpha = math.ceil(Util.lerp(self.__fadeTimer, 0, 0, halfDuration, 255)) -- fade out
self._isFadeOut = true
elseif self.__fadeTimer < fadeDuration then
fadeAlpha = Common.lerp(self.__fadeTimer, halfDuration, 255, fadeDuration, 0) -- fade in
fadeAlpha = math.ceil(Util.lerp(self.__fadeTimer, halfDuration, 255, fadeDuration, 0)) -- fade in
if self._isFadeOut then -- just switched to fading in, swap to new page
self.currentPage = self.currentPage + 1
end
self._isFadeOut = false
else
self.__fadeStarted = false -- fade done, reset variable
self._isTransitioning = false
self._isFadeOut = false
end
local fillColor = {table.unpack(fadeColor, 1, 3)} -- copy color table
@ -113,14 +126,26 @@ function SplashPage:drawBackground(deltaTime)
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)
if self.content[self.currentPage] then
self.content[self.currentPage]:render(deltaTime)
end
end
function SplashPage:drawForeground(deltaTime)
local textFillColor = {0, 0, 0}
if self.currentPage <= 1 then
textFillColor = {255, 255, 255}
end
if self._isTransitioning then
self:fadeTransition(deltaTime)
end
gfx.LoadSkinFont("segoeui.ttf")
gfx.FillColor(table.unpack(textFillColor))
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_BOTTOM)
gfx.FontSize(28)
gfx.Text("Press START to skip...", 10, Dim.design.height - 10)
end
return SplashPage

View File

@ -1,61 +1,54 @@
local Version = require('common.version')
local Dim = require("common.dimensions")
require "common.globals"
local Wallpaper = require("components.wallpaper")
local Version = require "common.version"
local Dim = require "common.dimensions"
local splash1Image = gfx.CreateSkinImage('titlescreen/title/background.png', 0)
local Image = require "api.image"
local triggerModeSelect = false
local triggerServiceMenu = false
local Page = require "api.page.page"
local versionString = Version.getLongVersion()
local function render(deltaTime)
Dim.updateResolution()
---@class TitlePage : Page
---@field background_img Image
local TitlePage = {
__name = "TitlePage",
BACKGROUND_IMG_PATH = "titlescreen/title/background.png",
}
Wallpaper.render()
function TitlePage.new(params)
local self = CreateInstance(TitlePage, params, Page)
Dim.transformToScreenSpace()
self.background_img = Image.new(self.BACKGROUND_IMG_PATH)
self.background_img:setPosition(0, 0)
self.background_img:setSize(Dim.design.width, Dim.design.height)
gfx.BeginPath()
gfx.ImageRect(0, 0, Dim.design.width, Dim.design.height, splash1Image, 1, 0)
gfx.LoadSkinFont("segoeui.ttf")
gfx.FillColor(255, 255, 255, 255)
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_TOP)
gfx.FontSize(28)
gfx.Text(versionString, 10, 10)
if (triggerModeSelect) then
triggerModeSelect = false
return {
eventType = 'switch',
toScreen = 'mode_select'
}
end
if (triggerServiceMenu) then
triggerServiceMenu = false
return {
eventType = 'switch',
toScreen = 'service'
}
end
return self
end
local function onButtonPressed(button)
function TitlePage:handleButtonInput(button)
if button == game.BUTTON_FXR and game.GetButton(game.BUTTON_FXL) or
button == game.BUTTON_FXL and game.GetButton(game.BUTTON_FXR) then
triggerServiceMenu = true
self:onInvalidation(true) -- true to switch to service menu
end
if button == game.BUTTON_STA then
triggerModeSelect = true
self:onInvalidation()
end
end
return {
render = render,
onButtonPressed = onButtonPressed
}
function TitlePage:drawBackground(deltaTime)
self.background_img:render()
end
function TitlePage:drawForeground(deltaTime)
gfx.LoadSkinFont("segoeui.ttf")
gfx.FillColor(255, 255, 255)
gfx.StrokeColor(0, 0, 0)
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT + gfx.TEXT_ALIGN_TOP)
gfx.FontSize(28)
gfx.StrokeWidth(1)
gfx.Text(versionString, 10, 10)
end
return TitlePage