feat(ui): 主菜单/暂停菜单屏幕状态机——中文标题「年糕历险记」、按钮点击、Esc 暂停(烟雾测试 10 秒无崩溃)

This commit is contained in:
NianGao Dev
2026-08-15 23:43:31 +08:00
parent 272f69b6a3
commit 6cc0f12079
4 changed files with 248 additions and 3 deletions

View File

@@ -45,6 +45,11 @@ type clientApp struct {
uiR *ui.Renderer
hud *ui.HUD
// 屏幕状态机:0 主菜单 / 1 游戏中 / 2 暂停(UI还原.md §2)
screen int
titleScreen *ui.TitleScreen
pauseScreen *ui.PauseScreen
meshBuilder *mesh.Builder
mu sync.Mutex
@@ -62,7 +67,46 @@ type worldMeshJob struct {
// Tick 每 tick(20Hz):输入 → 玩家 → 会话 → 网格构建(渲染.md §3.3 dirty 重建)。
func (a *clientApp) Tick(dt float64) {
// 输入 → 玩家速度(UI与输入.md §6 动作映射)
// 屏幕状态机(UI还原.md §2:主菜单/暂停不处理游戏输入)
switch a.screen {
case 0: // 主菜单
if a.in.clicked {
switch a.titleScreen.HitTest(a.in.clickX, a.in.clickY) {
case "play":
a.screen = 1
a.rend.SetCursorMode(true)
case "quit":
a.rend.Window().SetShouldClose(true)
}
a.in.clicked = false
}
a.in.dyaw, a.in.dpitch = 0, 0
return
case 2: // 暂停
if a.in.escPressed {
a.screen = 1
a.rend.SetCursorMode(true)
}
if a.in.clicked {
switch a.pauseScreen.HitTest(a.in.clickX, a.in.clickY) {
case "resume":
a.screen = 1
a.rend.SetCursorMode(true)
case "quit":
a.rend.Window().SetShouldClose(true)
}
a.in.clicked = false
}
a.in.escPressed = false
return
}
// 游戏中
if a.in.escPressed {
a.screen = 2
a.rend.SetCursorMode(false)
a.in.escPressed = false
return
}
a.in.apply(a.sess)
a.sess.Tick(dt)
@@ -107,7 +151,15 @@ func (a *clientApp) Render() {
a.rend.DrawChunks(func(i int) (int32, int32) { return chunks[i].CX, chunks[i].CZ }, len(chunks))
// UI pass(UI与输入.md §2:3D 之后、状态隔离)
a.uiR.Begin()
a.hud.Draw(a.uiR)
switch a.screen {
case 0:
a.titleScreen.Draw(a.uiR)
case 1:
a.hud.Draw(a.uiR)
case 2:
a.hud.Draw(a.uiR) // 暂停时世界仍可见(UI还原.md §2)
a.pauseScreen.Draw(a.uiR)
}
a.uiR.Flush()
a.rend.EndFrame()
}
@@ -250,6 +302,13 @@ func main() {
hud.SetItemAtlas(itemTex, itemUV)
}
// 界面屏幕(中文标题「年糕历险记」+ 按钮,UI还原.md §2)
lang, err := am.LoadLang(cfg.Client.Language)
if err != nil {
log.Warnf("语言加载失败: %v", err)
}
titleScreen, pauseScreen := buildScreens(uiR, lang)
// 6) 输入(鼠标捕获 + 键鼠回调)
in := newInputState(rend.Window())
@@ -260,6 +319,8 @@ func main() {
in: in,
uiR: uiR,
hud: hud,
titleScreen: titleScreen,
pauseScreen: pauseScreen,
meshBuilder: mesh.NewBuilder(reg, uvFn),
winW: cfg.Client.WindowWidth,
winH: cfg.Client.WindowHeight,