Files
ngzz-mc/internal/ui/options.go

124 lines
3.6 KiB
Go
Raw Normal View History

//go:build gl
// 设置界面(UI还原.md §2、UI与输入.md §6):
// 鼠标灵敏度 / 音量滑条 + 世界种子显示 + 按键教程列表 + 完成按钮。
// 滑条点击左/右半区为减/加;值由调用方持有并注入。
package ui
import (
"fmt"
)
// OptionsScreen 设置界面。
type OptionsScreen struct {
BtnTex uint32 // 原版按钮控件
BtnHover uint32
TitleTex uint32 // 「设置」标题
TitleW float32
TitleH float32
// CJK 标签与按键教程(构建时预光栅化)
SensLabelTex uint32
SensLabelW float32
SensLabelH float32
VolLabelTex uint32
VolLabelW float32
VolLabelH float32
ControlsTex uint32
ControlsW float32
ControlsH float32
SeedLabelTex uint32
SeedLabelW float32
SeedLabelH float32
DoneLabelTex uint32
DoneLabelW float32
DoneLabelH float32
}
// 滑条区域(屏幕像素,1280×720 布局)。
var (
optSensBar = [4]float32{540, 260, 200, 10}
optVolBar = [4]float32{540, 330, 200, 10}
optDone = [4]float32{540, 560, 200, 20}
)
// HitTest 命中检测:返回 "sens-"/"sens+"/"vol-"/"vol+"/"done"/""。
func (s *OptionsScreen) HitTest(mx, my float32) string {
hit := func(r [4]float32) bool {
return mx >= r[0] && mx < r[0]+r[2] && my >= r[1] && my < r[1]+r[3]
}
if hit(optSensBar) {
if mx < optSensBar[0]+optSensBar[2]/2 {
return "sens-"
}
return "sens+"
}
if hit(optVolBar) {
if mx < optVolBar[0]+optVolBar[2]/2 {
return "vol-"
}
return "vol+"
}
if hit(optDone) {
return "done"
}
return ""
}
// Draw 绘制设置界面(调用方已 Begin)。
func (s *OptionsScreen) Draw(r *Renderer, mx, my, sens, vol float32) {
w, h := float32(r.w), float32(r.h)
// 背景:土质暗色 + 标题
r.DrawRect(0, 0, w, h, [4]float32{0.10, 0.12, 0.10, 0.92})
if s.TitleTex != 0 {
r.pushQuad(quad{x: w/2 - s.TitleW/2, y: h * 0.10, w: s.TitleW, h: s.TitleH,
u0: 0, v0: 0, u1: 1, v1: 1, r: 1, g: 1, b: 1, a: 1, tex: s.TitleTex})
}
// 标签
s.blitLabel(r, s.SensLabelTex, s.SensLabelW, s.SensLabelH, 380, 255)
s.blitLabel(r, s.VolLabelTex, s.VolLabelW, s.VolLabelH, 380, 325)
// 滑条(底 + 填充 + 值)
s.drawSlider(r, optSensBar, sens)
s.drawSlider(r, optVolBar, vol)
// 世界种子
s.blitLabel(r, s.SeedLabelTex, s.SeedLabelW, s.SeedLabelH, 380, 395)
// 按键教程列表
s.blitLabel(r, s.ControlsTex, s.ControlsW, s.ControlsH, 380, 435)
// 完成按钮
hover := mx >= optDone[0] && mx < optDone[0]+optDone[2] && my >= optDone[1] && my < optDone[1]+optDone[3]
tex := s.BtnTex
if hover && s.BtnHover != 0 {
tex = s.BtnHover
}
if tex != 0 {
r.pushQuad(quad{x: optDone[0], y: optDone[1], w: optDone[2], h: optDone[3],
u0: 0, v0: 0, u1: 1, v1: 1, r: 1, g: 1, b: 1, a: 1, tex: tex})
}
if s.DoneLabelTex != 0 {
r.pushQuad(quad{x: optDone[0] + (optDone[2]-s.DoneLabelW)/2, y: optDone[1] + (optDone[3]-s.DoneLabelH)/2,
w: s.DoneLabelW, h: s.DoneLabelH, u0: 0, v0: 0, u1: 1, v1: 1,
r: 1, g: 1, b: 1, a: 1, tex: s.DoneLabelTex})
}
}
// drawSlider 绘制滑条:底轨 + 按比例填充 + 数值文本(0–1)。
func (s *OptionsScreen) drawSlider(r *Renderer, bar [4]float32, v float32) {
if v < 0 {
v = 0
}
if v > 1 {
v = 1
}
r.DrawRect(bar[0], bar[1], bar[2], bar[3], [4]float32{0.2, 0.2, 0.2, 1})
r.DrawRect(bar[0], bar[1], bar[2]*v, bar[3], [4]float32{0.4, 0.9, 0.4, 1})
r.DrawText(bar[0]+bar[2]+12, bar[1]-6, fmt.Sprintf("%.0f%%", v*100), 1, [4]float32{1, 1, 1, 1})
}
func (s *OptionsScreen) blitLabel(r *Renderer, tex uint32, w, h, x, y float32) {
if tex == 0 {
return
}
r.pushQuad(quad{x: x, y: y, w: w, h: h, u0: 0, v0: 0, u1: 1, v1: 1,
r: 1, g: 1, b: 1, a: 1, tex: tex})
}