完整课程入口:996 全套课程体系 | Lua 学习路径 | 幂尔框架 mirs.cn
背包是操作频率最高的系统:获得物品找空位、叠加物品合并堆、删除物品留空洞。背包系统的核心算法只有三个:查找可堆叠位置、分配空格子、删除后的空洞管理。算法写错的表现:物品消失、同物品拆成多堆、格子显示错位——全是高优先级客诉。
local Bag = { size = 40, slots = {} } -- slots[i] = { id=, count=, maxStack= } 或 nil
local function findStackable(id, count)
local cfg = itemCfg(id)
local remain = count
for i = 1, Bag.size do
local s = Bag.slots[i]
if s and s.id == id and s.count < cfg.maxStack then
local move = math.min(cfg.maxStack - s.count, remain)
s.count = s.count + move
remain = remain - move
if remain == 0 then return true end
end
end
for i = 1, Bag.size do
if not Bag.slots[i] then
local move = math.min(cfg.maxStack, remain)
Bag.slots[i] = { id = id, count = move }
remain = remain - move
if remain == 0 then return true end
end
end
return remain == 0, remain -- 返回未入包数量供上层处理
end
先扫可堆叠格合并,再找空格新堆,剩余数量返回给调用方(入包失败走邮件补发)。
删除按"指定格子删除"与"按物品数量删除"两种:前者用于定点消耗(任务回收指定格),后者从后往前扫描删除(避免 remove 造成的下标位移)。整理功能(一键排序)的实现:把全部物品按 id 聚合、重排堆叠、清空后重写格子数组——整理是一次性重建,比逐格搬移简单可靠。
三个必须的校验入口:每次增删后断言"格子总数 = 物品总数 / 堆叠上限的关系"(快速一致性检查);持久化时序列化整个 slots 数组(参考 string.pack 存档篇或 JSON);物品操作全部写流水(谁、何时、加减什么)。背包算法的 bug 直接等于资产 bug,一致性断言与流水审计是底线配置。
背包格子的客户端展示与服务端数据严格对齐:服务端是唯一事实源,客户端只渲染。任何客户端自行预测的物品变动(如先扣后补)都要在服务端确认后校正,不一致的窗口期控制在一秒内。
格子扩容后,新增格子的下标衔接在既有数组之后,历史物品位置不变。整理功能重排格子时要把迁移前后都写进流水,客户端断线重连后按服务端数据全量刷新,不依赖本地记忆。