- 音频(音频.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/ 布局)
74 lines
2.5 KiB
Go
74 lines
2.5 KiB
Go
// Package camera 第一人称相机:欧拉角(yaw/pitch)与视图/投影矩阵(渲染.md 配套)。
|
||
//
|
||
// 约定:yaw=0 朝向 -Z(GL 习惯),pitch>0 抬头;视图矩阵为列主序(GL 风格)。
|
||
package camera
|
||
|
||
import "math"
|
||
|
||
// Camera 第一人称相机。
|
||
type Camera struct {
|
||
Pos [3]float64 // 眼睛位置
|
||
Yaw float64 // 水平角(弧度)
|
||
Pitch float64 // 俯仰角(弧度)
|
||
FOV float64 // 垂直视场角(度)
|
||
}
|
||
|
||
// New 创建相机。
|
||
func New(pos [3]float64, yaw, pitch, fov float64) *Camera {
|
||
return &Camera{Pos: pos, Yaw: yaw, Pitch: pitch, FOV: fov}
|
||
}
|
||
|
||
// Forward 前方向(单位向量)。
|
||
func (c *Camera) Forward() [3]float64 {
|
||
cp, sp := math.Cos(c.Pitch), math.Sin(c.Pitch)
|
||
cy, sy := math.Cos(c.Yaw), math.Sin(c.Yaw)
|
||
return [3]float64{-sy * cp, sp, -cy * cp}
|
||
}
|
||
|
||
// Right 右方向(单位向量,水平)。
|
||
func (c *Camera) Right() [3]float64 {
|
||
cy, sy := math.Cos(c.Yaw), math.Sin(c.Yaw)
|
||
return [3]float64{cy, 0, -sy}
|
||
}
|
||
|
||
// View 视图矩阵(列主序 4×4,GL 用)。
|
||
// 推导:相机旋转 R = RotY(yaw)·RotX(pitch)(世界→相机为 Rᵀ = RotX(-pitch)·RotY(-yaw))。
|
||
// 视图 = Rᵀ·T(-pos)。
|
||
// 旧实现误用正向旋转 R:俯仰角符号被翻转(低头渲染成抬头),
|
||
// 表现是「视角不跟随鼠标上下移动」(上下视角失效根因)。
|
||
func (c *Camera) View() [16]float32 {
|
||
cp, sp := math.Cos(c.Pitch), math.Sin(c.Pitch)
|
||
cy, sy := math.Cos(c.Yaw), math.Sin(c.Yaw)
|
||
|
||
// V = RotX(-pitch)·RotY(-yaw),按列主序存储(列 0/1/2 为相机基在世界的分量)
|
||
var m [16]float32
|
||
m[0] = float32(cy) // col0.x
|
||
m[1] = float32(sp * sy) // col0.y
|
||
m[2] = float32(cp * sy) // col0.z
|
||
m[4] = 0 // col1.x
|
||
m[5] = float32(cp) // col1.y
|
||
m[6] = float32(-sp) // col1.z
|
||
m[8] = float32(-sy) // col2.x
|
||
m[9] = float32(sp * cy) // col2.y
|
||
m[10] = float32(cp * cy) // col2.z
|
||
m[15] = 1
|
||
// 平移:t = -V·pos
|
||
px, py, pz := float32(c.Pos[0]), float32(c.Pos[1]), float32(c.Pos[2])
|
||
m[12] = -(m[0]*px + m[4]*py + m[8]*pz)
|
||
m[13] = -(m[1]*px + m[5]*py + m[9]*pz)
|
||
m[14] = -(m[2]*px + m[6]*py + m[10]*pz)
|
||
return m
|
||
}
|
||
|
||
// Projection 透视投影矩阵(列主序,GL 用)。
|
||
func (c *Camera) Projection(aspect, near, far float64) [16]float32 {
|
||
f := 1.0 / math.Tan(c.FOV*math.Pi/360.0)
|
||
var m [16]float32
|
||
m[0] = float32(f / aspect)
|
||
m[5] = float32(f)
|
||
m[10] = float32((far + near) / (near - far))
|
||
m[11] = -1
|
||
m[14] = float32(2 * far * near / (near - far))
|
||
return m
|
||
}
|