140 lines
4.1 KiB
Go
140 lines
4.1 KiB
Go
//go:build gl
|
||
|
||
// 界面屏幕构建:原版复刻(UI还原.md §2)——土质背景、原版按钮控件、
|
||
// 中文标题「年糕历险记」、黄色 splash、版本/版权角标。
|
||
package main
|
||
|
||
import (
|
||
"image"
|
||
"image/color"
|
||
"image/draw"
|
||
"image/png"
|
||
"os"
|
||
"path/filepath"
|
||
|
||
"mc/internal/assets"
|
||
"mc/internal/cjkfont"
|
||
"mc/internal/ui"
|
||
)
|
||
|
||
// cjkPaths 系统 CJK 字体候选。
|
||
var cjkPaths = []string{
|
||
filepath.Join(os.Getenv("WINDIR"), "Fonts", "msyh.ttc"),
|
||
filepath.Join(os.Getenv("WINDIR"), "Fonts", "msyh.ttf"),
|
||
}
|
||
|
||
// loadCJK 加载系统 CJK 字体(失败返回 nil → 中文标签退化不显示)。
|
||
func loadCJK() *cjkfont.Renderer {
|
||
for _, p := range cjkPaths {
|
||
if _, err := os.Stat(p); err == nil {
|
||
if r, err := cjkfont.Load(p, 24); err == nil {
|
||
return r
|
||
}
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// buildScreens 构建主菜单与暂停菜单(原版布局与控件)。
|
||
func buildScreens(r *ui.Renderer, am *assets.Manager, lang *assets.Lang) (*ui.TitleScreen, *ui.PauseScreen) {
|
||
cjk := loadCJK()
|
||
|
||
// 原版按钮控件(widget/button.png 200×20 与悬停高亮)
|
||
loadPng := func(key string) (uint32, bool) {
|
||
p, ok := am.ResolveTexture(key)
|
||
if !ok {
|
||
return 0, false
|
||
}
|
||
f, err := os.Open(p)
|
||
if err != nil {
|
||
return 0, false
|
||
}
|
||
img, err := png.Decode(f)
|
||
_ = f.Close()
|
||
if err != nil {
|
||
return 0, false
|
||
}
|
||
return r.UploadImage(img), true
|
||
}
|
||
btnTex, _ := loadPng("gui/sprites/widget/button")
|
||
btnHover, _ := loadPng("gui/sprites/widget/button_highlighted")
|
||
|
||
// 土质背景:16px dirt 平铺 1280×720(原版菜单背景质感)
|
||
bgTex := tileBackground(r, am)
|
||
|
||
// 中文文本光栅化
|
||
text := func(s string, size float64, c color.RGBA) (uint32, float32, float32) {
|
||
if cjk == nil || s == "" {
|
||
return 0, 0, 0
|
||
}
|
||
img := cjk.Draw(s, c)
|
||
return r.UploadImage(img), float32(img.Bounds().Dx()), float32(img.Bounds().Dy())
|
||
}
|
||
tr := func(key, fallback string, size float64, c color.RGBA) (uint32, float32, float32) {
|
||
s := fallback
|
||
if lang != nil && lang.Get(key) != key {
|
||
s = lang.Get(key)
|
||
}
|
||
return text(s, size, c)
|
||
}
|
||
|
||
// 标题与 splash(原版:大标题 + 黄色 splash 于其右下)
|
||
titleTex, tw, th := tr("menu.title", "年糕历险记", 96, color.RGBA{255, 255, 255, 255})
|
||
splashTex, sw, sh := tr("menu.splash", "牛气冲天!", 24, color.RGBA{255, 255, 85, 255})
|
||
|
||
// 按钮(原版 200×20、间距 24、居中,UI还原.md §2 布局)
|
||
mkBtn := func(key, fallback, action string, y float32) ui.Button {
|
||
tex, lw, lh := tr(key, fallback, 18, color.RGBA{255, 255, 255, 255})
|
||
return ui.Button{X: 1280/2 - 100, Y: y, W: 200, H: 20, Tex: tex, LabelW: lw, LabelH: lh, Action: action}
|
||
}
|
||
title := &ui.TitleScreen{
|
||
TitleTex: titleTex, TitleW: tw, TitleH: th,
|
||
SplashTex: splashTex, SplashW: sw, SplashH: sh,
|
||
BgTex: bgTex, BtnTex: btnTex, BtnHover: btnHover,
|
||
Version: "年糕历险记 v0.1.0",
|
||
Copyright: "Copyright NianGao Studio. 请勿分发!",
|
||
}
|
||
title.Buttons = []ui.Button{
|
||
mkBtn("menu.singleplayer", "单人游戏", "play", 390),
|
||
mkBtn("menu.multiplayer", "多人游戏", "multi", 414),
|
||
mkBtn("menu.options", "设置…", "", 438),
|
||
mkBtn("menu.quit", "退出游戏", "quit", 462),
|
||
}
|
||
|
||
pauseTitle, ptw, pth := tr("menu.game", "游戏菜单", 32, color.RGBA{255, 255, 255, 255})
|
||
pause := &ui.PauseScreen{
|
||
TitleTex: pauseTitle, TitleW: ptw, TitleH: pth,
|
||
BtnTex: btnTex, BtnHover: btnHover,
|
||
}
|
||
pause.Buttons = []ui.Button{
|
||
mkBtn("gui.resume", "继续游戏", "resume", 300),
|
||
mkBtn("menu.quit", "保存并退出", "quit", 324),
|
||
}
|
||
return title, pause
|
||
}
|
||
|
||
// tileBackground 把 dirt 纹理平铺成全屏背景(像素风土墙)。
|
||
func tileBackground(r *ui.Renderer, am *assets.Manager) uint32 {
|
||
p, ok := am.ResolveTexture("block/dirt")
|
||
if !ok {
|
||
return 0
|
||
}
|
||
f, err := os.Open(p)
|
||
if err != nil {
|
||
return 0
|
||
}
|
||
tile, err := png.Decode(f)
|
||
_ = f.Close()
|
||
if err != nil {
|
||
return 0
|
||
}
|
||
const w, h = 1280, 720
|
||
bg := image.NewRGBA(image.Rect(0, 0, w, h))
|
||
for y := 0; y < h; y += 16 {
|
||
for x := 0; x < w; x += 16 {
|
||
draw.Draw(bg, image.Rect(x, y, x+16, y+16), tile, image.Point{}, draw.Src)
|
||
}
|
||
}
|
||
return r.UploadImage(bg)
|
||
}
|