Pink 编程第二弹 背包系统,大型暗黑APRG游戏制作中

背包系统 点我观看视频

背包系统设计文档 (除了网络协议转发,数据库存储, 前后端逻辑UI 全部由Pink自己改写的,包括prefab 我自己手动改了一点内容)

目录

  1. 系统概述

  2. 核心组件

  3. 网格系统

  4. 物品管理

  5. 装备槽位系统

  6. 拖拽交互

  7. 网络协议

  8. 事件系统


系统概述

背包系统是一个基于网格的物品管理系统,支持不同尺寸的物品放置、拖拽移动、装备穿戴/卸下、物品丢弃等功能。

主要特性

  • 网格化背包:10×4 的网格布局,支持多格物品

  • 装备槽位:10个装备槽位,支持拖拽穿戴/卸下

  • 实时高亮:拖拽时显示可放置区域的高亮提示

  • 服务器验证:所有操作需要服务器确认,失败时自动回滚


核心组件

1. BagPage.ts

背包页面主控制器,负责:

  • 网格创建和管理

  • 物品节点的创建和销毁

  • 装备槽位初始化

  • 事件监听和处理

  • 拖拽高亮显示

2. BackpackItem.ts

背包物品组件,负责:

  • 物品的拖拽交互

  • 触摸事件处理(点击/拖拽区分)

  • 物品尺寸管理

  • 图标和名称显示

3. EquipSlotItem.ts

装备槽位组件,负责:

  • 装备槽位的显示和高亮

  • 装备图标的拖拽

  • 槽位类型匹配检测

4. ItemData.ts / UserItem.ts

数据管理类,负责:

  • 物品配置数据

  • 用户物品数据

  • 背包数据列表管理


网格系统

网格配置


GRID_SIZE = 48      // 单个格子尺寸(像素)

GRID_WIDTH = 10     // 横向格子数

GRID_HEIGHT = 4     // 纵向格子数

GRID_OFFSET_Y = 192 // 网格Y轴偏移(GRID_SIZE * 4)

ITEM_OFFSET_Y = 20  // 物品Y轴偏移修正

坐标系统

  • 网格坐标:左上角为 (0, 0),向右为X正方向,向下为Y正方向

  • 本地坐标:节点中心为原点的标准坐标系

坐标转换方法


// 网格坐标 → 本地坐标

gridToLocalX(gridX, itemWidth)      // X轴转换

gridToLocalY(gridY, itemHeight)     // Y轴转换(用于网格)

gridToItemLocalY(gridY, itemHeight) // Y轴转换(用于物品,含偏移修正)

// 本地坐标 → 网格坐标

getGridPosition(itemNode)           // 返回 { gridX, gridY }

网格占用管理


usedSlots: Map<string, Node>  // key: "x,y", value: 占用该格子的物品节点


物品管理

物品属性

| 属性 | 类型 | 说明 |

|------|------|------|

| series | any | 物品唯一序列号 |

| item_id | number | 物品配置ID |

| width | number | 物品宽度(格子数) |

| height | number | 物品高度(格子数) |

| posX | number | 网格X坐标 |

| posY | number | 网格Y坐标 |

| num | number | 物品数量 |

| storage_id | number | 存储位置(0=背包) |

物品操作

创建物品


createItem(itemCfg, uItem, series): Node

  • 实例化物品预制体

  • 设置尺寸、序列号、图标

  • 添加到背包节点

放置物品


onNetAddPlaceItem(itemNode, gridX, gridY)  // 网络添加

tryPlaceItem(itemNode): boolean             // 尝试放置

  • 边界检查

  • 碰撞检测

  • 更新位置和存储

移除物品


removeItemFromStorage(itemNode)           // 清理网格占用

removeItemFromStorageByGrid(itemNode, gridX, gridY)  // 按坐标清理

丢弃物品


tryDiscardItem(itemNode): boolean

  • 仅背包物品可丢弃,装备槽位装备不可丢弃

  • 弹出确认弹窗

  • 确认后发送删除请求

  • 服务器返回后销毁节点


装备槽位系统

槽位配置

| SlotIndex | 槽位名称 | 节点属性 |

|-----------|----------|----------|

| 1 | 左手(武器) | equipSlot_weapon |

| 2 | 右手(盾牌) | equipSlot_shield |

| 3 | 衣服(胸甲) | equipSlot_chestarmor |

| 4 | 帽子(头盔) | equipSlot_headarmor |

| 5 | 手套 | equipSlot_glove |

| 6 | 鞋 | equipSlot_boots |

| 7 | 项链(护符) | equipSlot_amulet |

| 8 | 左戒 | equipSlot_ring1 |

| 9 | 右戒 | equipSlot_ring2 |

| 10 | 腰带 | equipSlot_belt |

槽位操作

穿戴装备


tryEquipItemToSlot(itemNode, worldPos): boolean

  1. 检测悬停的槽位

  2. 验证装备类型匹配

  3. 验证使用条件(等级等)

  4. 隐藏物品节点,禁用触摸事件

  5. 发送穿戴请求

  6. 等待服务器确认

卸下装备


tryUnequipToBag(worldPos, series, itemWidth, itemHeight): boolean

  1. 计算目标网格坐标

  2. 验证位置有效性

  3. 发送卸下请求

  4. 等待服务器确认

槽位高亮


updateEquipSlotHoverHighlight(itemNode, worldPos)  // 更新高亮

clearEquipSlotHighlight()                          // 清除高亮

  • 绿色:可装备

  • 红色:不可装备


拖拽交互

背包物品拖拽流程


┌─────────────────┐

│  TOUCH_START    │

│  记录起始位置    │

└────────┬────────┘

         │

         ▼

┌─────────────────┐

│  TOUCH_MOVE     │

│  超过阈值(5px)? │

└────────┬────────┘

         │

    ┌────┴────┐

    │ 是      │ 否

    ▼         ▼

┌───────┐  ┌───────┐

│ 拖拽  │  │ 等待  │

│ 模式  │  │       │

└───┬───┘  └───────┘

    │

    ▼

┌─────────────────┐

│ 清理旧位置存储   │

│ 更新高亮显示     │

│ 检测装备槽位     │

└────────┬────────┘

         │

         ▼

┌─────────────────┐

│  TOUCH_END      │

└────────┬────────┘

         │

    ┌────┴────────────┬─────────────────┐

    │                 │                 │

    ▼                 ▼                 ▼

┌───────────┐  ┌───────────┐  ┌───────────┐

│ 装备槽位  │  │ 背包外    │  │ 背包内    │

│ 穿戴装备  │  │ 丢弃物品  │  │ 移动物品  │

└───────────┘  └───────────┘  └───────────┘

装备槽位拖拽流程


┌─────────────────┐

│  TOUCH_START    │

│  检查是否有装备  │

└────────┬────────┘

         │

         ▼

┌─────────────────┐

│  TOUCH_MOVE     │

│  创建拖拽图标   │

│  更新背包高亮   │

└────────┬────────┘

         │

         ▼

┌─────────────────┐

│  TOUCH_END      │

└────────┬────────┘

         │

    ┌────┴────┐

    │         │

    ▼         ▼

┌───────┐  ┌───────┐

│背包内 │  │背包外 │

│卸下   │  │无操作 │

│装备   │  │(不可  │

│       │  │丢弃)  │

└───────┘  └───────┘

         │

         ▼

┌─────────────────┐

│  销毁拖拽图标   │

└─────────────────┘

高亮颜色


Colors = {

    DEFAULT: Color(180, 180, 180),  // 默认

    VALID: Color.GREEN,              // 可放置

    INVALID: Color.RED,              // 不可放置

    OCCUPIED: Color.BLUE             // 已占用

}


网络协议

物品移动 (Protocol 6)


// 请求:移动物品

CSMoveItemReq {

    series: ItemSeries,  // 物品序列号

    posX: number,        // 目标X坐标

    posY: number         // 目标Y坐标

}

// 响应:移动结果

事件: BagViewEventType.MOVE_ITEM_RESULT

data: { series, result }  // result: 1=成功

装备穿戴 (Protocol 7-1)


// 请求:穿戴装备

CSFitOutEquip {

    series: ItemSeries,  // 物品序列号

    slot: number,        // 槽位索引

    type: number         // 0=玩家, 1=英雄

}

// 响应:穿戴结果

事件: EquipEventType.EQUIP_RESULT

data: { result }  // result: 1=成功

装备卸下 (Protocol 7-3)


// 请求:卸下装备到指定位置

CSTakeOffEquipToPos {

    series: ItemSeries,  // 装备序列号

    posX: number,        // 背包X坐标

    posY: number         // 背包Y坐标

}

物品删除 (Protocol 6)


// 请求:删除物品

CSDeleteItemReq {

    series: ItemSeries   // 物品序列号

}

// 响应:删除成功

事件: ItemEventType.ITEM_DEL / BAG_ITEM_DEL

装备删除 (Protocol 7-6)


// 响应:删除装备

SCDelOneEquip {

    series: ItemSeries   // 装备序列号

}


事件系统

物品事件 (ItemEventType)

| 事件名 | 说明 |

|--------|------|

| ITEM_ADD | 物品添加 |

| ITEM_DEL | 物品删除 |

| ITEM_CHANGE | 物品变化 |

| BAG_ITEM_ADD | 背包物品添加 |

| BAG_ITEM_DEL | 背包物品删除 |

| BAG_ITEM_CHANGE | 背包物品变化 |

| ITEM_LIST | 物品列表更新 |

背包事件 (BagViewEventType)

| 事件名 | 说明 |

|--------|------|

| MOVE_ITEM_RESULT | 移动物品结果 |

| FLUSH_BAG_GRID | 刷新背包格子 |

| UPDATE_BAG_GRID | 更新背包格子 |

装备事件 (EquipEventType)

| 事件名 | 说明 |

|--------|------|

| EQUIP_RESULT | 装备穿戴结果 |

对象事件 (ObjectEventType)

| 事件名 | 说明 |

|--------|------|

| EQUIP_DATA_CHANGE | 装备数据变化 |

| MAIN_ROLE_ATTR_CHANGE | 主角属性变化 |


待确认机制

物品移动待确认


pendingMoveItems: Map<string, {

    itemNode: Node,

    oldGridX: number,

    oldGridY: number,

    newGridX: number,

    newGridY: number

}>

  • 移动成功:更新 startPos

  • 移动失败:还原到原位置

装备穿戴待确认


pendingEquipItem: {

    itemNode: Node,

    slotIndex: number,

    series: any

} | null

  • 穿戴成功:销毁物品节点

  • 穿戴失败:恢复显示,还原位置,重新注册事件


文件结构


assets/scripts/game/bag/

├── BagPage.ts          # 背包页面主控制器

├── BackPackItem.ts     # 背包物品组件

├── EquipSlotItem.ts    # 装备槽位组件

├── BagCtrl.ts          # 背包控制器(网络请求)

├── ItemData.ts         # 物品数据管理

└── UserItem.ts         # 用户物品数据结构

assets/scripts/gameui/ui/role/

├── RoleController.ts   # 角色控制器(装备协议处理)

├── EquipData.ts        # 装备数据管理

└── RoleData.ts         # 角色数据

assets/scripts/game/protocol/

├── Protocol6.ts        # 物品相关协议

└── Protocol7.ts        # 装备相关协议


注意事项

  1. 服务器验证:所有物品操作都需要服务器确认,客户端只做预处理

  2. 碰撞检测:放置物品前必须检查目标区域是否被占用

  3. 边界检查:物品不能超出背包网格范围

  4. 装备限制:装备槽位的装备不可丢弃,只能卸下到背包

  5. 事件清理:物品节点销毁前需要移除触摸事件监听

  6. 坐标一致性:网格坐标和本地坐标转换时注意偏移量


文档版本: 1.0

最后更新: 2026年2月3日

1赞

:partying_face::partying_face::partying_face:666

做得很好,那么为什么防腐之首在头部呢? :joy:

image
没啥关系吧…注释时间都不改 2022-04-04