- 音频(音频.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/ 布局)
84 lines
2.2 KiB
Go
84 lines
2.2 KiB
Go
// Package cjkfont 中文字体渲染:加载系统 CJK 字体(微软雅黑)光栅化文本(UI还原.md §4 中文回退)。
|
||
//
|
||
// 素材包位图字体只含 ASCII;中文(如「年糕历险记」)用系统字体渲染,
|
||
// 保持像素风(最近邻采样、整数缩放),字形不追求与原版一致。
|
||
package cjkfont
|
||
|
||
import (
|
||
"image"
|
||
"image/color"
|
||
"os"
|
||
"strings"
|
||
|
||
"golang.org/x/image/font"
|
||
"golang.org/x/image/font/opentype"
|
||
"golang.org/x/image/math/fixed"
|
||
)
|
||
|
||
// Renderer CJK 文本渲染器。
|
||
type Renderer struct {
|
||
face font.Face
|
||
}
|
||
|
||
// Load 加载字体文件(如 C:\Windows\Fonts\msyh.ttc)。
|
||
func Load(path string, sizePx float64) (*Renderer, error) {
|
||
data, err := os.ReadFile(path)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// 兼容 .ttc 字体集合(如 msyh.ttc)与单字体 .ttf/.otf
|
||
var f *opentype.Font
|
||
if col, err := opentype.ParseCollection(data); err == nil && col != nil && col.NumFonts() > 0 {
|
||
f, err = col.Font(0)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
} else {
|
||
f, err = opentype.Parse(data)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
face, err := opentype.NewFace(f, &opentype.FaceOptions{
|
||
Size: sizePx,
|
||
DPI: 72,
|
||
Hinting: font.HintingNone,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &Renderer{face: face}, nil
|
||
}
|
||
|
||
// Width 文本像素宽度。
|
||
func (r *Renderer) Width(s string) int {
|
||
d := &font.Drawer{Face: r.face}
|
||
return d.MeasureString(s).Ceil()
|
||
}
|
||
|
||
// Draw 渲染文本为 RGBA 图像(含 1px 阴影,UI还原.md §4;支持 \n 多行)。
|
||
func (r *Renderer) Draw(s string, c color.RGBA) image.Image {
|
||
lineH := int(r.face.Metrics().Height.Ceil()) + 1
|
||
ascent := int(r.face.Metrics().Ascent.Ceil())
|
||
lines := strings.Split(s, "\n")
|
||
w := 0
|
||
for _, ln := range lines {
|
||
if lw := r.Width(ln) + 1; lw > w {
|
||
w = lw
|
||
}
|
||
}
|
||
img := image.NewRGBA(image.Rect(0, 0, w, lineH*len(lines)))
|
||
for i, ln := range lines {
|
||
y0 := i * lineH
|
||
// 阴影
|
||
sh := &font.Drawer{Dst: img, Src: image.NewUniform(color.RGBA{10, 10, 10, 220}), Face: r.face}
|
||
sh.Dot = fixed.P(1, y0+ascent+1)
|
||
sh.DrawString(ln)
|
||
// 正文
|
||
d := &font.Drawer{Dst: img, Src: image.NewUniform(c), Face: r.face}
|
||
d.Dot = fixed.P(0, y0+ascent)
|
||
d.DrawString(ln)
|
||
}
|
||
return img
|
||
}
|