fix(game): 崩溃修复(卸载区块实体冻结)+ 立面光照、掉落可见、打击感、水下效果、空手拳头、血条左/饥饿右
- 崩溃(index out of range):实体所在区块卸载后失去碰撞支撑无限下坠到 负坐标,光查询越界 panic——WorldView 增 ChunkLoaded,未加载区块实体冻结; chunk 光查询加越界防御(双保险) - 立面光照:mesh 每面取**邻格**光照(原版光照模型)——此前用方块自身光照 (sky=0)导致悬崖/矿洞立面全黑(泥土竖向黑色根因) - 掉落可见:生成后 1 秒拾取延迟 + 图标加大到 0.45 - 打击感:攻击命中音(block.hit)+ 实体受击白闪(uTint)+ 手持挥动动画 - 水下效果:相机入水蓝色叠加(渲染.md §8 水体) - 空手显示肤色拳头(白羊毛 × 肤色 tint),持方块正常显示 - HUD 布局:血条左下、饥饿右下(经典布局)
This commit is contained in:
@@ -3,6 +3,7 @@ package entity
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 掉落物参数(实体系统.md §5)。
|
||||
@@ -13,10 +14,14 @@ const (
|
||||
dropPerChunk = 32 // 每区块掉落物上限
|
||||
)
|
||||
|
||||
// dropPickupDelay 生成后可拾取延迟(测试可置 0)。
|
||||
var dropPickupDelay = time.Second
|
||||
|
||||
// Drop 掉落物实体数据。
|
||||
type Drop struct {
|
||||
Item string
|
||||
Count int
|
||||
Born time.Time // 生成时刻(1 秒内不可拾取,掉落可见期)
|
||||
}
|
||||
|
||||
// SpawnDrop 生成掉落物:同物品近距合并(上限 dropStackMax);超上限丢弃。
|
||||
@@ -48,7 +53,7 @@ func (m *Manager) SpawnDrop(itemName string, count int, x, y, z float64) {
|
||||
}
|
||||
m.next++
|
||||
e := &Entity{ID: m.next, Kind: KindItemDrop, Pos: [3]float64{x, y, z}, Health: 1,
|
||||
Data: &Drop{Item: itemName, Count: count}}
|
||||
Data: &Drop{Item: itemName, Count: count, Born: time.Now()}}
|
||||
e.Vel = [3]float64{(rand01(e.ID) - 0.5) * 2, 4, (rand01(e.ID>>16) - 0.5) * 2} // 弹出初速度
|
||||
m.entities[e.ID] = e
|
||||
m.drops[itemName] = e
|
||||
@@ -62,6 +67,7 @@ func rand01(seed ID) float64 {
|
||||
}
|
||||
|
||||
// PickupNearby 拾取玩家附近掉落物,返回拾取的物品列表(实体系统.md §5 拾取)。
|
||||
// 生成后 1 秒内不可拾取(掉落可见期,与原版一致)。
|
||||
func (m *Manager) PickupNearby(px, py, pz float64) []Drop {
|
||||
var out []Drop
|
||||
for _, e := range m.List() {
|
||||
@@ -72,6 +78,9 @@ func (m *Manager) PickupNearby(px, py, pz float64) []Drop {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if time.Since(d.Born) < dropPickupDelay {
|
||||
continue // 新鲜掉落:可拾取延迟(掉落可见)
|
||||
}
|
||||
dx, dy, dz := e.Pos[0]-px, e.Pos[1]-py, e.Pos[2]-pz
|
||||
if dx*dx+dy*dy+dz*dz < dropPickupDist*dropPickupDist {
|
||||
e.Dead = true
|
||||
|
||||
@@ -33,6 +33,9 @@ type WorldView interface {
|
||||
Block(x, y, z int32) block.State
|
||||
SkyLight(x, y, z int32) uint8
|
||||
BlockLight(x, y, z int32) uint8
|
||||
// ChunkLoaded 实体所在区块是否已加载(卸载区块冻结实体——
|
||||
// 否则实体失去碰撞支撑会无限下坠到负数坐标,见 实体系统.md §2)
|
||||
ChunkLoaded(x, z int32) bool
|
||||
}
|
||||
|
||||
// Entity 实体。
|
||||
@@ -45,6 +48,9 @@ type Entity struct {
|
||||
Health float64
|
||||
Dead bool
|
||||
|
||||
// HitFlash 受击白闪剩余秒数(客户端渲染用,打击反馈)
|
||||
HitFlash float64
|
||||
|
||||
// AI 状态(实体系统.md §3 状态机)
|
||||
state uint8
|
||||
decisionIn float64 // 下次决策倒计时(限频)
|
||||
@@ -116,12 +122,19 @@ func (m *Manager) List() []*Entity {
|
||||
return out
|
||||
}
|
||||
|
||||
// Tick 每 tick 更新全部实体(激活区块内;冻结区由调用方过滤)。
|
||||
// Tick 每 tick 更新全部实体(激活区块内;冻结区跳过,实体系统.md §2
|
||||
// ——未加载区块无碰撞支撑,实体继续 tick 会无限下坠并越界崩溃)。
|
||||
func (m *Manager) Tick(dt float64, w WorldView, playerPos [3]float64) {
|
||||
for _, e := range m.List() {
|
||||
if e.Dead {
|
||||
continue
|
||||
}
|
||||
if !w.ChunkLoaded(int32(e.Pos[0]), int32(e.Pos[2])) {
|
||||
continue // 区块卸载:冻结
|
||||
}
|
||||
if e.HitFlash > 0 {
|
||||
e.HitFlash -= dt // 受击白闪衰减
|
||||
}
|
||||
switch e.Kind {
|
||||
case KindZombie:
|
||||
e.tickZombie(dt, w, playerPos)
|
||||
|
||||
@@ -17,6 +17,7 @@ func (flatWorld) Solid(x, y, z int32) bool { return y < 63 }
|
||||
func (flatWorld) Block(x, y, z int32) block.State { return block.Air }
|
||||
func (flatWorld) SkyLight(x, y, z int32) uint8 { return 15 }
|
||||
func (flatWorld) BlockLight(x, y, z int32) uint8 { return 0 }
|
||||
func (flatWorld) ChunkLoaded(x, z int32) bool { return true }
|
||||
|
||||
// TestZombieChase 僵尸追玩家(僵尸与敌对生物.md §2)。
|
||||
func TestZombieChase(t *testing.T) {
|
||||
@@ -64,6 +65,8 @@ func TestAnimalWander(t *testing.T) {
|
||||
|
||||
// TestDropMerge 掉落物合并(实体系统.md §5)。
|
||||
func TestDropMerge(t *testing.T) {
|
||||
dropPickupDelay = 0 // 测试跳过拾取延迟
|
||||
defer func() { dropPickupDelay = time.Second }()
|
||||
m := NewManager()
|
||||
m.SpawnDrop("cobblestone", 5, 0.5, 64, 0.5)
|
||||
m.SpawnDrop("cobblestone", 5, 0.6, 64, 0.5) // 距离 <1 → 合并
|
||||
|
||||
Reference in New Issue
Block a user