- 音频(音频.md §2):Session.Sound 事件回调,破坏/放置/攻击/村民环境音接入, 客户端 audio.Manager 3D 衰减 + 监听器跟随 + 音量可调 - 原版掉落:草方块→泥土、石头→圆石、树叶无掉落(no_drop);掉落物实体 用物品图标小广告牌渲染(物品纹理并入实体图集) - 动物攻击(动物体系.md §5):左键优先射线命中实体(半径 0.6 球体判定), 伤害/击退/死亡移除+肉类掉落;僵尸掉腐肉 - 村庄村民(村民系统.md §2):Generator.VillageAt 定位村庄中心,会话扫描 已加载区块在村庄生成 3 名村民 - 种子与灵敏度配置:client.yaml world.seed/name、mouse_sensitivity; 存档与种子联动;鼠标左右反转修复(右移应右转) - 设置界面(UI与输入.md §6):屏幕状态 4,灵敏度/音量滑条、世界种子显示、 按键教程多行列表(cjkfont 支持 \\n)、完成按钮;主菜单/暂停菜单入口 - 准星指向方块名:左下角 CJK 显示(lang 本地化,tick 光栅化渲染线程上传) - 截图统一存项目根目录 jietu/(paths.RootDir;dev 构建识别 bin/ 布局)
124 lines
3.6 KiB
Go
124 lines
3.6 KiB
Go
//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})
|
||
}
|