//go:build gl // 实体可视映射:实体类型 → 贴图键/身高/动物模型(渲染.md §5.3)。 // 动物用方块组合模型(身体+头+四腿)近似原版外观;僵尸/村民用交叉广告牌; // 掉落物用物品图标小广告牌。 package main import ( "mc/internal/entity" "mc/internal/item" "mc/internal/render" ) // entityVisual 返回实体的贴图键与身高(米)。 // 动物额外返回外观变体(0 牛 / 1 猪 / 2 羊 / 3 鸡),供方块模型选择。 func entityVisual(e *entity.Entity, items *item.Registry) (key string, height float32, variant int) { switch e.Kind { case entity.KindZombie: return "entity/zombie/zombie", 1.95, -1 case entity.KindVillager: return "entity/villager/villager", 1.95, -1 case entity.KindAnimal: switch e.ID % 4 { case 0: return "entity/cow/cow_temperate", 1.4, 0 case 1: return "entity/pig/pig_temperate", 0.9, 1 case 2: return "entity/sheep/sheep", 1.3, 2 default: return "entity/chicken/chicken_temperate", 0.7, 3 } case entity.KindItemDrop: d, ok := e.Data.(*entity.Drop) if !ok || items == nil { return "", 0, -1 } def, ok := items.Get(d.Item) if !ok { return "", 0, -1 } return def.Texture, 0.45, -1 default: return "", 0, -1 } } // rect 构造图集 tile 内归一化子矩形。 func rect(u0, v0, u1, v1 float32) [4]float32 { return [4]float32{u0, v0, u1, v1} } // boxPart 构造模型部件:六面统一用 side 矩形,前/后取中间条带,顶取上条带,底取下条带。 func boxPart(cx, cy, cz, w, h, d float32, side [4]float32) render.AnimalPart { u0, v0, u1, v1 := side[0], side[1], side[2], side[3] uw, vh := u1-u0, v1-v0 front := rect(u0+uw*0.35, v0, u0+uw*0.65, v1) // 前/后面:中间三分之一 top := rect(u0, v0, u1, v0+vh*0.3) bottom := rect(u0, v1-vh*0.3, u1, v1) var uv [6][4]float32 // 顺序同 cubeFaces:顶/底/东/西/南(前)/北(后) uv[0], uv[1] = top, bottom uv[2], uv[3] = side, side uv[4], uv[5] = front, front return render.AnimalPart{CX: cx, CY: cy, CZ: cz, W: w, H: h, D: d, UV: uv} } // animalModel 返回动物方块模型(variant:0 牛 / 1 猪 / 2 羊 / 3 鸡)。 // 贴图子矩形按原版皮肤布局:头部在纹理左侧、身体在右侧、腿在下部。 // 图集 tile 内纹理被等比拉伸成 64×64(64×32 原图纵向拉长一倍,矩形已按拉伸后比例折算)。 func animalModel(variant int) render.AnimalModel { switch variant { case 0: // 牛:纹理 64×64,内容在上半(v 0–0.5) head := rect(0.02, 0.02, 0.48, 0.48) body := rect(0.52, 0.02, 0.98, 0.48) legs := rect(0.55, 0.30, 0.98, 0.50) var m render.AnimalModel m.Parts = append(m.Parts, boxPart(0, 0.72, 0, 0.92, 0.62, 1.28, body), boxPart(0, 1.26, 0.60, 0.56, 0.50, 0.56, head), boxPart(-0.34, 0.24, 0.50, 0.22, 0.48, 0.22, legs), boxPart(0.34, 0.24, 0.50, 0.22, 0.48, 0.22, legs), boxPart(-0.34, 0.24, -0.50, 0.22, 0.48, 0.22, legs), boxPart(0.34, 0.24, -0.50, 0.22, 0.48, 0.22, legs), ) return m case 1: // 猪:纹理 64×64,内容在上半 head := rect(0.14, 0.03, 0.48, 0.45) body := rect(0.52, 0.03, 0.98, 0.45) legs := rect(0.60, 0.30, 0.98, 0.50) var m render.AnimalModel m.Parts = append(m.Parts, boxPart(0, 0.50, 0, 0.76, 0.44, 1.02, body), boxPart(0, 0.86, 0.50, 0.50, 0.42, 0.50, head), boxPart(-0.28, 0.15, 0.42, 0.18, 0.30, 0.18, legs), boxPart(0.28, 0.15, 0.42, 0.18, 0.30, 0.18, legs), boxPart(-0.28, 0.15, -0.42, 0.18, 0.30, 0.18, legs), boxPart(0.28, 0.15, -0.42, 0.18, 0.30, 0.18, legs), ) return m case 2: // 羊:纹理 64×32(tile 内 v 拉长一倍) head := rect(0.02, 0.02, 0.26, 0.40) body := rect(0.50, 0.15, 1.00, 0.72) legs := rect(0.62, 0.50, 0.95, 0.85) var m render.AnimalModel m.Parts = append(m.Parts, boxPart(0, 0.72, 0, 0.92, 0.60, 1.26, body), boxPart(0, 1.20, 0.60, 0.50, 0.46, 0.50, head), boxPart(-0.33, 0.21, 0.50, 0.20, 0.42, 0.20, legs), boxPart(0.33, 0.21, 0.50, 0.20, 0.42, 0.20, legs), boxPart(-0.33, 0.21, -0.50, 0.20, 0.42, 0.20, legs), boxPart(0.33, 0.21, -0.50, 0.20, 0.42, 0.20, legs), ) return m default: // 鸡:纹理 64×32 head := rect(0.02, 0.05, 0.28, 0.55) body := rect(0.28, 0.10, 0.70, 0.75) legs := rect(0.30, 0.55, 0.60, 0.80) var m render.AnimalModel m.Parts = append(m.Parts, boxPart(0, 0.36, 0, 0.44, 0.40, 0.52, body), boxPart(0, 0.66, 0.24, 0.32, 0.30, 0.32, head), boxPart(-0.14, 0.10, 0.18, 0.09, 0.20, 0.09, legs), boxPart(0.14, 0.10, 0.18, 0.09, 0.20, 0.09, legs), ) return m } }