Files
ngzz-mc/internal/entity/drops.go

84 lines
2.1 KiB
Go
Raw Normal View History

// 掉落物实体:合并与拾取(实体系统.md §5)。
package entity
import (
"math"
)
// 掉落物参数(实体系统.md §5)。
const (
dropMergeDist = 1.0 // 同物品合并距离
dropStackMax = 64 // 合并上限
dropPickupDist = 1.5 // 拾取半径
dropPerChunk = 32 // 每区块掉落物上限
)
// Drop 掉落物实体数据。
type Drop struct {
Item string
Count int
}
// SpawnDrop 生成掉落物:同物品近距合并(上限 dropStackMax);超上限丢弃。
func (m *Manager) SpawnDrop(itemName string, count int, x, y, z float64) {
if count <= 0 {
return
}
m.mu.Lock()
defer m.mu.Unlock()
// 合并
if old, ok := m.drops[itemName]; ok && !old.Dead {
dx, dz := old.Pos[0]-x, old.Pos[2]-z
if math.Sqrt(dx*dx+dz*dz) < dropMergeDist {
if d, ok := old.Data.(*Drop); ok && d.Count+count <= dropStackMax {
d.Count += count
return
}
}
}
// 上限检查
drops := 0
for _, e := range m.entities {
if e.Kind == KindItemDrop {
drops++
}
}
if drops >= dropPerChunk*8 { // 全局粗上限(按区块过滤后置)
return
}
m.next++
e := &Entity{ID: m.next, Kind: KindItemDrop, Pos: [3]float64{x, y, z}, Health: 1,
Data: &Drop{Item: itemName, Count: count}}
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
}
// Data 实体附加数据。
// rand01 实体 ID 派生确定性随机(掉落初速度用,存档回放一致)。
func rand01(seed ID) float64 {
const mod = 1000003
return float64(seed%mod) / mod
}
// PickupNearby 拾取玩家附近掉落物,返回拾取的物品列表(实体系统.md §5 拾取)。
func (m *Manager) PickupNearby(px, py, pz float64) []Drop {
var out []Drop
for _, e := range m.List() {
if e.Kind != KindItemDrop || e.Dead {
continue
}
d, ok := e.Data.(*Drop)
if !ok {
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
m.Remove(e.ID)
out = append(out, *d)
}
}
return out
}