Files
ngzz-mc/internal/entity/drops.go
NianGao Dev 5d0524ca52 feat(game): 掉落物单堆叠上限 9999 + 拾取按栈上限拆分;挖掘按住循环挥动
- 地上掉落合并上限 64→9999,超出生成新堆(TestDropStackCap)
- 拾取按物品栈上限拆成多栈入包,放不下回吐地面
- 按住左键挖掘时每 0.3 秒循环挥动手部(swingTimer),
  挥动幅度收窄并抬高持手位置保持可见
- 新增 -digtest/-swingtest dev 截图测试开关
2026-08-16 22:32:07 +08:00

93 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 掉落物实体:合并与拾取(实体系统.md §5)。
package entity
import (
"math"
"time"
)
// 掉落物参数(实体系统.md §5)。
const (
dropMergeDist = 1.0 // 同物品合并距离
dropStackMax = 9999 // 单堆叠合并上限(地上大堆;拾取时按背包栈上限拆分)
dropPickupDist = 1.5 // 拾取半径
dropPerChunk = 32 // 每区块掉落物上限
)
// dropPickupDelay 生成后可拾取延迟(测试可置 0)。
var dropPickupDelay = time.Second
// Drop 掉落物实体数据。
type Drop struct {
Item string
Count int
Born time.Time // 生成时刻(1 秒内不可拾取,掉落可见期)
}
// 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, 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
}
// Data 实体附加数据。
// rand01 实体 ID 派生确定性随机(掉落初速度用,存档回放一致)。
func rand01(seed ID) float64 {
const mod = 1000003
return float64(seed%mod) / mod
}
// PickupNearby 拾取玩家附近掉落物,返回拾取的物品列表(实体系统.md §5 拾取)。
// 生成后 1 秒内不可拾取(掉落可见期,与原版一致)。
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
}
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
m.Remove(e.ID)
out = append(out, *d)
}
}
return out
}