2.背包物品系统设计与实现

2.背包物品系统设计与实现


2.1 系统架构设计

整个背包物品系统采用分层架构,职责分明,各层之间高内聚、低耦合:

  • 数据层:定义物品与背包的数据模型,负责持久化存储与加载。
  • 逻辑层:封装物品管理、背包操作、筛选与红点提示等业务逻辑。
  • 服务层:提供跨模块调用的接口,如物品创建、发放、使用、交易等。
  • 表现层:UI 界面与交互组件,将数据和逻辑结果可视化呈现给玩家。
graph TD
    A[背包物品系统] --> B[数据层]
    A --> C[逻辑层]
    A --> D[服务层]
    A --> E[表现层]
    
    B --> B1[物品配置数据]
    B --> B2[背包状态数据]
    B --> B3[持久化存储]
    
    C --> C1[物品管理逻辑]
    C --> C2[背包操作逻辑]
    C --> C3[物品行为逻辑]
    
    D --> D1[物品相关服务]
    D --> D2[背包相关服务]
    D --> D3[交互相关服务]
    
    E --> E1[背包UI界面]
    E --> E2[背包详情]
    E --> E3[物品详情]
    E --> E4[交互逻辑触发]
    E --> E5[交互反馈]

2.2 核心模块关系

核心模块关系图

graph LR
    %% ====== 核心架构 ======
    A[玩家实体] --> C(库存组件)
    A --> B(玩家物品组件)
    D(全局物品管理器) --> K[物品配置数据]

    %% ====== 全局物品管理器 ======
    D --> D1[物品配置管理]
    D --> D2[物品工厂]
    D --> D3[物品行为注册表]
    D3a[原子行为库]

    %% ====== 玩家库存组件 ======
    C --> C1[背包分类管理]
    C --> C2[快捷栏管理]
    C --> C3[合成系统]
    C1 --> L1[装备背包]
    C1 --> L2[消耗品背包]
    C1 --> L3[材料背包]
    L1 --> M1[物品实例]
    L2 --> M2[物品实例]
    L3 --> M3[物品实例]

    %% ====== 玩家物品组件 ======
    B --> B1[玩家状态上下文]
    B --> B2[属于玩家的个性化物品逻辑]
    B2 -.-> D3a

    %% ====== 数据交互链路 ======
    K --> N[全局物品操作接口]
    N --> P[数据持久化]
    C --> O[库存操作接口]
    O --> P
    B --> B3[玩家物品操作接口]
    B3 --> P

    %% ====== 行为执行链路 ======
    M1 -.-> D3
    D3 -.-> D3a

    %% ====== 样式定义 ======
    classDef player fill:#FFD1DC,stroke:#FF69B4,stroke-width:2px;
    classDef logic fill:#E6FFED,stroke:#6DD59D,stroke-width:2px;
    classDef data fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef container fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
    classDef global fill:#B0E2FF,stroke:#1E90FF,stroke-width:2px;
    classDef item fill:#FFEBCD,stroke:#FFA500,stroke-width:2px;

    %% ====== 样式应用 ======
    class A player;
    class C,C1,C2,C3,O logic;
    class B,B2,B3 logic;
    class D,D1,D2,D3,N logic;
    class K,P,B1,D3a data;
    class L1,L2,L3 container;
    class M1,M2,M3 item;
    class D global;

核心模块职责说明

全局物品管理器(全局唯一)

  • 物品配置管理:统一维护物品基础属性(ID/名称/类型/图标等),支持配置热更新
  • 物品工厂:基于配置创建物品实例,支持堆叠规则、品质等级等复杂逻辑
  • 行为注册表
    • 注册物品原子行为(如”回复HP”、”增加攻击力”)
    • 维护行为ID与执行逻辑的映射关系
  • 原子行为库
    • 存储可复用的原子行为数据(行为ID/参数模板/效果描述)
    • 支持通过ID组合实现复合行为(如混合药剂同时触发多个原子行为)

玩家物品组件(玩家专属)

  • 状态上下文
    • 存储玩家与物品相关的个性化状态(已收集物品记录/职业限制/等级条件)
    • 维护物品使用历史与状态变更记录
  • 个性化逻辑引擎
    • 基于玩家状态过滤可使用物品(如职业专属装备)
    • 动态组合原子行为(如”战士使用斧头时强化劈砍行为”)
    • 触发条件式行为(如”低血量时自动使用红药”)

玩家库存组件(玩家专属)

  • 容器管理体系
    • 背包分类管理:按类型(装备/消耗品/材料)分区存储物品实例
    • 快捷栏管理:支持物品与操作槽的绑定/解绑
    • 合成系统:验证配方合法性并执行合成逻辑
  • 实例生命周期管理
    • 处理物品添加/移除/堆叠/拆分等操作
    • 维护物品实例的引用计数与状态同步
  • 规则引擎
    • 支持自动整理(同类物品合并/品质排序)
    • 触发库存状态变化事件(如背包满时通知玩家)

核心机制说明

原子行为组合机制

flowchart TB
    物品使用请求 --> 行为注册表解析[根据物品ID获取行为ID列表]
    行为注册表解析 --> 原子行为调度[按顺序执行行为ID序列]
    原子行为调度 --> 玩家状态上下文[获取玩家状态参数]
    玩家状态上下文 --> 原子行为执行[带入玩家参数执行行为]
    原子行为执行 --> 库存状态更新[如消耗品数量减少]
  • 示例实现
    • 红药配置行为列表:[ID:101](对应”回复生命值”原子行为)
    • 蓝药配置行为列表:[ID:102](对应”回复法力值”原子行为)
    • 混合药剂配置行为列表:[ID:101, ID:102](顺序执行双回复)

关键设计说明

  1. 全局与局部分离
    • 全局管理器保证物品配置与基础行为的一致性
    • 玩家组件支持个性化逻辑(如职业专属、状态触发)
  2. 数据与行为解耦
    • 物品配置独立于实例,支持热更新
    • 原子行为可复用,通过配置组合实现复杂效果
  3. 容器化管理
    • 背包/快捷栏/合成系统统一为容器接口

2.3 核心数据模型

核心数据模型类图

classDiagram
    %% 接口定义
    class IItem {
        +Id: Guid; 唯一标识符
        +Name: string; 物品名称
        +StackCount: int; 当前堆叠数量
        +MaxStackSize: int; 最大堆叠数量
        +IsStackable: bool; 是否可堆叠
        +BehaviorIds: List; 行为ID列表
        +CanUse(): bool; 能否使用物品
        +Use(): bool; 使用物品
        +Combine(other: IItem): bool; 合并物品
    }



    class IAtomBehavior {
        +BehaviorId: int; 行为唯一标识
        +Execute(context: PlayerItemContext, parameters: Dictionary): bool; 执行原子行为
        +GetDescription(): string; 获取行为描述
    }

    %% 基类定义
    class ItemBase {
        +Id: Guid; 自动生成的实例ID
        +ConfigId: int; 配置表的物品ID
        +Name: string; 物品名称
        +Description: string; 物品描述
        +Type: ItemType; 物品类型
        +Rarity: ItemRarity; 物品品质
        +StackCount: int; 当前堆叠数
        +IsStackable: bool; 是否可堆叠
        +MaxStackSize: int; 最大堆叠数
        +BehaviorIds: List; 关联的行为ID列表
        +Properties: Dictionary; 扩展属性
        +Initialize(configId: int, count: int): void; 初始化物品
        +CanUse(): bool; 能否使用物品
        +Use(): bool; 使用物品抽象方法
        +Combine(other: IItem): bool; 合并物品逻辑
    }


    %% 原子行为相关
    class BehaviorRegistry {
        -behaviorMap: Dictionary; 行为ID映射表
        +RegisterBehavior(behavior: IAtomBehavior): void; 注册行为
        +GetBehavior(behaviorId: int): IAtomBehavior; 获取行为
        +GetBehaviors(ids: List): List; 批量获取行为
    }

    class PlayerItemContext {
        +playerId: Guid; 玩家ID
        +level: int; 玩家等级
        +职业: string; 玩家职业
        +HP: int; 生命值
        +MP: int; 魔法值
        +attributes: AttributeSet; 基础属性
        +GetState(key: string): object; 获取状态值
        +SetState(key: string, value: object): void; 设置状态值
    }

    %% 子类定义
    class ConsumableItem {
        +EffectValue: int; 消耗品效果值
        +Use(): bool; 消耗品使用逻辑
    }

    class EquipmentItem {
        +Slot: EquipmentSlot; 装备部位
        +Modifiers: AttributeSet; 装备属性加成
        +Equip(): bool; 装备穿戴
        +Unequip(): bool; 装备脱下
    }

    class HealHPBehavior {
        +BehaviorId: int = 101; 回复生命值行为ID
        +HealAmount: int; 回复量
        +Execute(context: PlayerItemContext, parameters: Dictionary): bool; 执行治疗
    }

    class AddAttackBehavior {
        +BehaviorId: int = 201; 增加攻击力行为ID
        +BonusValue: int; 加成值
        +Duration: int; 持续时间(秒)
        +Execute(context: PlayerItemContext, parameters: Dictionary): bool; 执行加成
    }



    %% 关系定义
    IItem <|.. ItemBase
    ItemBase <|-- ConsumableItem
    ItemBase <|-- EquipmentItem

    IAtomBehavior <|.. HealHPBehavior
    IAtomBehavior <|.. AddAttackBehavior
    
    ItemBase "1" *-- "0..*" int: BehaviorIds
    BehaviorRegistry "1" o-- "0..*" IAtomBehavior: behaviorMap
    ItemBase "1" --> "1" BehaviorRegistry: 使用行为注册表
    IAtomBehavior "1" --> "1" PlayerItemContext: 依赖玩家状态
classDiagram

%% 接口定义
class IInventory {
    +Id: Guid; 背包唯一标识
    +Capacity: int; 背包容量
    +ItemCount: int; 当前物品数量
    +IsFull: bool; 是否已满
    +Items: IEnumerable<IItem>; 物品集合
    +AddItem(item: IItem): bool; 添加物品
    +RemoveItem(itemId: Guid, count: int): bool; 移除物品
    +ContainsItem(itemId: Guid): bool; 检查是否包含物品
    +GetItem(itemId: Guid): IItem; 获取物品
    +GetItemsByType(type: ItemType): IEnumerable<IItem>; 按类型获取物品
    +Clear(): void; 清空背包
}

%% 背包基类
class InventoryBase {
    +Id: Guid; 背包ID
    +Name: string; 背包名称
    +Capacity: int; 背包容量
    #slots: List<IItem>; 物品槽位集合
    +AddItem(item: IItem): bool; 添加物品
    +RemoveItem(itemId: Guid, count: int): bool; 移除物品
    +ContainsItem(itemId: Guid): bool; 检查物品存在
    +GetItem(itemId: Guid): IItem; 获取物品
    +GetItemsByType(type: ItemType): IEnumerable<IItem>; 按类型查询
    +Clear(): void; 清空背包
    #CanAddItem(item: IItem): bool; 检查是否可添加
}

%% 关系定义
IInventory <|.. InventoryBase
classDiagram
    %% 枚举类型
    class ItemType {
        -Consumable: int; 消耗品
        -Equipment: int; 装备
        -Material: int; 材料
        -Currency: int; 货币
        -QuestItem: int; 任务物品
    }

    class ItemRarity {
        -Common: int; 普通
        -Uncommon: int; 稀有
        -Rare: int; 史诗
        -Legendary: int; 传说
    }

    class EquipmentSlot {
        -Head: int; 头部
        -Chest: int; 胸部
        -Weapon: int; 武器
        -Legs: int; 腿部
        -Feet: int; 脚部
    }

    class AttributeSet {
        +Attack: int; 攻击力
        +Defense: int; 防御力
        +HP: int; 生命值
        +MP: int; 魔法值
        +Speed: int; 速度
    }

核心数据模型说明

原子行为体系整合

  • IAtomBehavior接口:定义原子行为的标准契约,包含执行方法和描述获取,与核心模块中的「原子行为库」对应
  • BehaviorRegistry类:实现行为ID与原子行为的映射管理,对应全局物品管理器中的「行为注册表」
  • ItemBase.BehaviorIds:存储物品关联的行为ID列表,实现配置表与行为的解耦,符合「数据与行为解耦」设计原则

与系统架构的对应关系

  • 数据层体现
    • ItemBase中的BehaviorIds对应「物品配置数据」中的行为配置
    • PlayerItemContext存储玩家物品相关状态数据(也可能会和玩家背包状态相关。所以其实也可以传个PlayerId逻辑里自己Get一下不同组件)
  • 逻辑层体现
    • HealHPBehavior等原子行为实现属于「物品行为逻辑」
    • BehaviorRegistry的注册/查询逻辑属于「物品管理逻辑」
  • 服务层关联
    • Item.Use()方法通过BehaviorRegistry调用行为,形成「物品相关服务」的执行链路

2.4 核心逻辑实现

物品管理逻辑实现

物品管理逻辑负责物品的创建、配置加载及类型扩展,对应系统架构中的逻辑层-物品管理逻辑

/// <summary>
/// 全局物品管理器,对应核心模块中的「全局物品管理器」
/// </summary>
public class GlobalItemManager : Singleton<GlobalItemManager>
{
    private Dictionary<int, ItemConfig> _itemConfigs;       // 物品配置字典(可选,或者封装一层从配置中心拿配置的接口)
    private BehaviorRegistry _behaviorRegistry;            // 行为注册表
    
    public override void Initialize()
    {
        _itemConfigs = ConfigLoader.Load<ItemConfig>(ConfigPath.ITEM_CONFIG);
        _behaviorRegistry = new BehaviorRegistry();
        
        // 注册基础原子行为 或者子类自己注册而非初始化注册所有
        _behaviorRegistry.RegisterBehavior(new HealHPBehavior());
        _behaviorRegistry.RegisterBehavior(new AddAttackBehavior());
        
        base.Initialize();
    }
    
    /// <summary>
    /// 物品工厂方法,对应「物品工厂」模块
    /// </summary>
    public ItemBase CreateItem(int configId, int count = 1)
    {
        if (!_itemConfigs.ContainsKey(configId))
            throw new ItemConfigNotFoundException(configId);
            
        var config = _itemConfigs[configId];
        ItemBase itemInstance;
        
        // 根据物品类型创建不同实例,支持扩展新类型
        switch (config.Type)
        {
            case ItemType.Consumable:
                itemInstance = new ConsumableItem();
                break;
            case ItemType.Equipment:
                itemInstance = new EquipmentItem();
                break;
            case ItemType.Material:
                itemInstance = new MaterialItem();
                break;
            default:
                itemInstance = new ItemBase();
                break;
        }
        
        // 初始化物品基础属性
        itemInstance.Initialize(configId, count);
        
        // 关联行为ID列表(从配置中获取)
        itemInstance.BehaviorIds = config.BehaviorIds;
        return itemInstance;
    }
    
    /// <summary>
    /// 获取行为注册表,供物品使用行为时调用
    /// </summary>
    public BehaviorRegistry GetBehaviorRegistry()
    {
        return _behaviorRegistry;
    }
}

玩家库存组件(管理多个背包)

/// <summary>
/// 玩家库存组件实现,管理多个不同类型的背包容器
/// 对应核心模块中的「玩家库存组件」
/// </summary>
public class PlayerInventoryComponent : Component
{
    private Guid _playerId;
    private Dictionary<InventoryType, IInventory> _inventories;
    private PlayerItemContext _context;
    
    public PlayerInventoryComponent(Guid playerId, PlayerItemContext context)
    {
        _playerId = playerId;
        _context = context;
        _inventories = new Dictionary<InventoryType, IInventory>();
        
        // 初始化默认背包
        InitializeDefaultInventories();
    }
    
    // 初始化默认背包(主背包、装备栏等)
    private void InitializeDefaultInventories()
    {
        // 主背包
        AddInventory(InventoryType.MainBag, new Inventory(50));
        
        // 装备栏
        AddInventory(InventoryType.Equipment, new EquipmentInventory(10));
        
        // 快捷栏
        AddInventory(InventoryType.QuickSlots, new QuickSlotInventory(8));
    }
    
    // 添加新背包类型
    public void AddInventory(InventoryType type, IInventory inventory)
    {
        _inventories[type] = inventory;
    }
    
    // 获取特定类型的背包
    public IInventory GetInventory(InventoryType type)
    {
        if (_inventories.TryGetValue(type, out var inventory))
            return inventory;
            
        return null;
    }
    
    // 在背包间移动物品
    public bool MoveItemBetweenInventories(
        InventoryType sourceType, 
        Guid sourceItemId, 
        InventoryType targetType, 
        int targetSlot = -1)
    {
        var sourceInventory = GetInventory(sourceType);
        var targetInventory = GetInventory(targetType);
        
        if (sourceInventory == null || targetInventory == null)
            return false;
            
        var item = sourceInventory.GetItem(sourceItemId);
        if (item == null)
            return false;
            
        // 从源背包移除
        if (!sourceInventory.RemoveItem(sourceItemId))
            return false;
            
        // 添加到目标背包
        bool success = targetSlot >= 0 
            ? targetInventory.AddItemToSlot(item, targetSlot)
            : targetInventory.AddItem(item);
            
        if (!success)
        {
            // 添加失败则放回源背包
            sourceInventory.AddItem(item);
            return false;
        }
        
        return true;
    }
    
    // 自动整理所有背包
    public void AutoArrangeAllInventories()
    {
        foreach (var inventory in _inventories.Values)
        {
            inventory.AutoArrange();
        }
    }
}

具体背包容器实现

实现背包容器,背包操作逻辑处理物品的存储、检索与状态管理,对应逻辑层-背包操作逻辑

/// <summary>
/// 基础背包容器实现,实现IInventory接口
/// </summary>
public class Inventory : IInventory
{
    public Guid Id { get; }
    public string Name { get; set; }
    public int Capacity { get; protected set; }
    protected List<IItem> _items;
    
    public Inventory(int capacity, string name = "背包")
    {
        Id = Guid.NewGuid();
        Name = name;
        Capacity = capacity;
        _items = new List<IItem>(capacity);
    }
    
    public bool AddItem(IItem item)
    {
        // 检查容量
        if (_items.Count >= Capacity)
            return false;
            
        // 尝试堆叠已有物品
        if (item.IsStackable)
        {
            foreach (var existingItem in _items)
            {
                if (existingItem.CanCombine(item))
                {
                    existingItem.Combine(item);
                    if (item.StackCount <= 0)
                        return true;
                }
            }
        }
        
        // 添加新物品
        _items.Add(item);
        return true;
    }
    
    // 其他IInventory接口方法实现...
}

/// <summary>
/// 装备背包,特殊处理装备的穿戴和卸下
/// </summary>
public class EquipmentInventory : Inventory
{
    public EquipmentInventory(int capacity) : base(capacity, "装备栏")
    {
        // 初始化固定槽位
        _items = new List<IItem>(new IItem[capacity]);
    }
    
    public bool EquipItem(IItem item, int slotIndex)
    {
        if (slotIndex < 0 || slotIndex >= Capacity)
            return false;
            
        // 卸下当前槽位物品
        var currentItem = _items[slotIndex];
        if (currentItem != null)
        {
            UnequipItem(slotIndex);
        }
        
        // 装备新物品
        _items[slotIndex] = item;
        
        // 触发装备事件
        EventBus.Publish(new ItemEquippedEvent(item, slotIndex));
        return true;
    }
    
    public IItem UnequipItem(int slotIndex)
    {
        if (slotIndex < 0 || slotIndex >= Capacity)
            return null;
            
        var item = _items[slotIndex];
        if (item != null)
        {
            _items[slotIndex] = null;
            EventBus.Publish(new ItemUnequippedEvent(item, slotIndex));
        }
        return item;
    }
}

/// <summary>
/// 快捷栏背包,支持物品与操作槽绑定
/// </summary>
public class QuickSlotInventory : Inventory
{
    private Dictionary<int, Action> _actionBindings;
    
    public QuickSlotInventory(int capacity) : base(capacity, "快捷栏")
    {
        _actionBindings = new Dictionary<int, Action>();
    }
    
    public bool BindAction(int slotIndex, Action action)
    {
        if (slotIndex < 0 || slotIndex >= Capacity)
            return false;
            
        _actionBindings[slotIndex] = action;
        return true;
    }
    
    public bool ExecuteAction(int slotIndex)
    {
        if (_actionBindings.TryGetValue(slotIndex, out var action))
        {
            action?.Invoke();
            return true;
        }
        return false;
    }
}

背包分类管理实现

/// <summary>
/// 背包分类管理器,支持按类型过滤物品
/// </summary>
public class InventoryCategoryManager
{
    private PlayerInventoryComponent _playerInventory;
    
    public InventoryCategoryManager(PlayerInventoryComponent inventory)
    {
        _playerInventory = inventory;
    }
    
    // 获取特定类型的所有物品
    public List<IItem> GetItemsByCategory(ItemType category)
    {
        var result = new List<IItem>();
        
        // 遍历所有背包
        foreach (var inventory in _playerInventory.GetAllInventories())
        {
            result.AddRange(inventory.GetItemsByType(category));
        }
        
        return result;
    }
    
    // 获取特定分类背包中的物品
    public List<IItem> GetItemsInCategoryBag(InventoryType categoryBag)
    {
        var inventory = _playerInventory.GetInventory(categoryBag);
        if (inventory == null)
            return new List<IItem>();
            
        return inventory.GetAllItems().ToList();
    }
}

原子行为逻辑实现

原子行为逻辑处理物品效果的执行,对应逻辑层-物品行为逻辑

/// <summary>
/// 行为注册表实现,对应核心模块「行为注册表」
/// </summary>
public class BehaviorRegistry
{
    private Dictionary<int, IAtomBehavior> _behaviorMap;  // 行为ID映射表
    
    public BehaviorRegistry()
    {
        // 也可能要读配置初始化注册实例化
        _behaviorMap = new Dictionary<int, IAtomBehavior>();
    }
    
    /// <summary>
    /// 注册原子行为
    /// </summary>
    public void RegisterBehavior(IAtomBehavior behavior)
    {
        if (_behaviorMap.ContainsKey(behavior.BehaviorId))
        {
            Debug.LogWarning($"行为ID {behavior.BehaviorId} 已存在,将覆盖");
        }
        _behaviorMap[behavior.BehaviorId] = behavior;
    }
    
    /// <summary>
    /// 获取原子行为实例
    /// </summary>
    public IAtomBehavior GetBehavior(int behaviorId)
    {
        if (_behaviorMap.TryGetValue(behaviorId, out var behavior))
        {
            return behavior;
        }
        throw new BehaviorNotFoundException(behaviorId);
    }
    
    /// <summary>
    /// 批量获取行为列表
    /// </summary>
    public List<IAtomBehavior> GetBehaviors(List<int> behaviorIds)
    {
        var behaviors = new List<IAtomBehavior>();
        foreach (var id in behaviorIds)
        {
            behaviors.Add(GetBehavior(id));
        }
        return behaviors;
    }
}

/// <summary>
/// 回复生命值原子行为实现
/// </summary>
public class HealHPBehavior : IAtomBehavior
{
    public int BehaviorId => 101;  // 行为ID需与配置一致
    public int HealAmount { get; set; }  // 回复量(可从配置获取)
    
    public HealHPBehavior(int healAmount = 100)
    {
        HealAmount = healAmount;
    }
    
    /// <summary>
    /// 执行治疗行为,依赖玩家状态上下文
    /// </summary>
    public bool Execute(PlayerItemContext context, Dictionary<string, object> parameters)
    {
        if (context == null) return false;
        
        // 从上下文中获取玩家当前HP
        int currentHP = context.GetState<int>("HP");
        int maxHP = context.GetState<int>("MaxHP");
        
        // 计算治疗后HP
        int newHP = Math.Min(currentHP + HealAmount, maxHP);
        context.SetState("HP", newHP);
        
        // 记录行为日志(可观测性设计)
        LogManager.LogBehaviorExecution(
            context.PlayerId, 
            BehaviorId, 
            new { HealAmount, NewHP = newHP }
        );
        
        return true;
    }
    
    public string GetDescription()
    {
        return $"回复 {HealAmount} 点生命值";
    }
}

服务层接口实现

服务层提供跨模块调用接口,对应服务层-物品相关服务/背包相关服务

/// <summary>
/// 物品服务接口,封装物品相关操作
/// </summary>
public class ItemService
{
    private GlobalItemManager _itemManager;
    private PlayerInventoryManager _inventoryManager;
    
    public ItemService()
    {
        _itemManager = GlobalItemManager.Instance;
        _inventoryManager = PlayerInventoryManager.Instance;
    }
    
    /// <summary>
    /// 发放物品给玩家(跨模块接口)
    /// </summary>
    public bool GiveItemToPlayer(Guid playerId, int configId, int count = 1)
    {
        // 1. 创建物品实例
        var item = _itemManager.CreateItem(configId, count);
        if (item == null) return false;
        
        // 2. 获取玩家背包
        var inventory = _inventoryManager.GetPlayerInventory(playerId);
        if (inventory == null) return false;
        
        // 3. 添加到背包
        bool success = inventory.AddItem(item);
        if (success)
        {
            // 4. 记录物品获取日志(可观测性)
            LogManager.LogItemObtained(playerId, configId, count);
            
            // 5. 触发背包更新事件(通知UI)
            EventBus.Publish(new ItemObtainedEvent(playerId, configId, count));
        }
        return success;
    }
    
    /// <summary>
    /// 使用物品(触发原子行为)
    /// </summary>
    public bool UseItem(Guid playerId, Guid itemId)
    {
        // 1. 获取玩家背包
        var inventory = _inventoryManager.GetPlayerInventory(playerId);
        if (inventory == null) return false;
        
        // 2. 获取物品实例
        var item = inventory.GetItem(itemId);
        if (item == null) return false;
        
        // 3. 检查物品是否可使用(可添加额外校验,如等级/职业限制)
        if (!item.CanUse()) return false;
        
        // 4. 获取玩家状态上下文
        var playerContext = _inventoryManager.GetPlayerContext(playerId);
        if (playerContext == null) return false;
        
        // 5. 执行物品行为逻辑
        bool useSuccess = item.Use();
        if (useSuccess)
        {
            // 6. 执行原子行为(从物品BehaviorIds获取并执行)
            ExecuteItemBehaviors(item, playerContext);
            
            // 7. 移除消耗品(如果已用完)
            if (item.StackCount <= 0)
            {
                inventory.RemoveItem(itemId);
            }
        }
        return useSuccess;
    }
    
    /// <summary>
    /// 执行物品关联的原子行为
    /// </summary>
    private void ExecuteItemBehaviors(IItem item, PlayerItemContext context)
    {
        var behaviorRegistry = _itemManager.GetBehaviorRegistry();
        var behaviorIds = item.BehaviorIds;
        
        foreach (var behaviorId in behaviorIds)
        {
            try
            {
                // 1. 从注册表获取行为
                var behavior = behaviorRegistry.GetBehavior(behaviorId);
                
                // 2. 准备行为参数(可从物品属性或玩家状态获取)
                var parameters = new Dictionary<string, object>
                {
                    { "ItemId", item.Id },
                    { "ConfigId", item.ConfigId }
                };
                
                // 3. 执行行为
                behavior.Execute(context, parameters);
            }
            catch (Exception e)
            {
                // 行为执行异常处理(保证主流程不中断)
                Debug.LogError($"执行行为 {behaviorId} 时发生异常: {e.Message}");
            }
        }
    }
}

核心流程序列图

物品使用流程

sequenceDiagram
    participant UI as 玩家界面
    participant ItemService as 物品服务
    participant PlayerInventory as 玩家背包
    participant ItemBase as 物品实例
    participant BehaviorRegistry as 行为注册表
    participant HealHPBehavior as 治疗行为
    participant PlayerItemContext as 玩家状态上下文
    
    UI->>ItemService: 请求使用物品(itemId)
    ItemService->>PlayerInventory: 获取物品实例
    PlayerInventory-->>ItemService: 返回物品实例
    ItemService->>ItemBase: 调用CanUse()
    ItemBase-->>ItemService: 返回是否可使用
    alt 可使用
        ItemService->>ItemBase: 调用Use()
        ItemBase-->>ItemService: 返回使用结果
        ItemService->>BehaviorRegistry: 获取行为列表
        BehaviorRegistry-->>ItemService: 返回行为实例
        ItemService->>PlayerItemContext: 获取玩家状态
        PlayerItemContext-->>ItemService: 返回状态参数
        ItemService->>HealHPBehavior: 执行行为
        HealHPBehavior->>PlayerItemContext: 更新玩家HP
        PlayerItemContext-->>HealHPBehavior: 状态更新完成
        HealHPBehavior-->>ItemService: 行为执行结果
        ItemService->>PlayerInventory: 移除消耗品
        PlayerInventory-->>ItemService: 移除结果
        ItemService->>UI: 通知更新背包
    else 不可使用
        ItemService->>UI: 显示错误提示
    end

原子行为组合执行流程

sequenceDiagram
    participant ItemUse as 物品使用请求
    participant BehaviorRegistry as 行为注册表
    participant Behavior1 as 原子行为1
    participant Behavior2 as 原子行为2
    participant PlayerContext as 玩家状态上下文
    
    ItemUse->>BehaviorRegistry: 获取行为列表[ID1, ID2]
    BehaviorRegistry->>Behavior1: 获取行为ID1
    BehaviorRegistry->>Behavior2: 获取行为ID2
    Behavior1->>PlayerContext: 获取状态参数
    PlayerContext-->>Behavior1: 返回参数
    Behavior1->>Behavior1: 执行行为1
    Behavior1-->>ItemUse: 行为1完成
    Behavior2->>PlayerContext: 获取状态参数
    PlayerContext-->>Behavior2: 返回参数(可能已变更)
    Behavior2->>Behavior2: 执行行为2
    Behavior2-->>ItemUse: 行为2完成
    ItemUse->>ItemUse: 组合行为执行完毕

核心逻辑实现与架构对应关系说明

  1. 分层架构映射

    • 数据层ItemConfigPlayerItemContext 负责数据模型定义
    • 逻辑层GlobalItemManagerPlayerInventory 封装核心业务逻辑
    • 服务层ItemService 提供跨模块调用接口
    • 表现层:通过 EventBus 事件驱动UI更新(未在代码中展示具体UI实现)
  2. 核心模块对应

    • 全局物品管理器:由 GlobalItemManager 实现,包含物品工厂和行为注册表
    • 玩家库存组件:由 PlayerInventory 实现,管理物品实例生命周期
    • 玩家物品组件:通过 PlayerItemContext 和行为执行逻辑体现
  3. 原子行为机制

    • 物品通过 BehaviorIds 关联行为ID列表
    • BehaviorRegistry 维护行为ID与执行逻辑的映射
    • 行为执行时依赖 PlayerItemContext 中的玩家状态
    • 支持复合行为按顺序执行,如混合药剂同时触发多个治疗行为
  4. 可扩展性设计

    • 新物品类型:继承 ItemBase 并实现专属逻辑
    • 新原子行为:实现 IAtomBehavior 接口并注册到注册表
    • 背包扩展:继承 PlayerInventory 实现仓库、快捷栏等特殊背包

2.5 性能优化手段

  • 对象池技术:复用物品实例、UI组件(如ItemCell)、原子行为实例,减少GC开销
  • 多维度索引:ID/类型/行为ID三重索引,加速物品查询与筛选
  • 脏数据标记:变更时标记脏数据,批量同步减少数据库IO
  • 多级缓存:可以使用多级缓存,例如使用内存+Redis做成多级缓存。
  • 懒加载与虚拟化:仅加载可视区域物品数据,数据库可以尝试分页。UI使用虚拟列表动态渲染

2.6 扩展性设计

  • 新背包类型:实现IInventory接口即可扩展(如仓库/公会背包),由PlayerInventoryComponent统一管理
  • 原子行为扩展:实现IAtomBehavior接口并注册到BehaviorRegistry,支持复合行为配置(原子行为一般也会有配置表)。
  • 物品类型扩展:继承ItemBase实现新类型(如任务物品/限时物品),重写核心方法

2.7 可观测性与安全

  • 操作日志:记录物品关键操作,支持问题追溯
  • 服务器验证:所有背包操作二次校验,服务端权威,防止客户端作弊

2.8 总结

本文从分层架构模块关系数据模型核心逻辑优化与扩展,系统地剖析了游戏背包系统的通用设计思路与实现示例。读者可根据具体需求,灵活增删模块、调整策略,以满足项目个性化需求。

  • 分层清晰:数据层、逻辑层、服务层、表现层各司其职,既保证了职责分明,又方便后续维护与测试。
  • 模块解耦:全局物品管理器与玩家专属组件分离,原子行为通过注册表驱动,数据与行为解耦,灵活组合行为。
  • 可扩展性:无论是新增物品类型、原子行为,还是扩展背包容器,都只需依赖统一接口即可平滑拓展。
  • 性能与安全:按需对象池、懒加载、多级缓存等策略,配合操作日志和服务器二次校验。可提升了效率以及强化安全可观测性。

注意:本文示例聚焦设计模式与扩展理念,生产环境请细化异常处理、并发安全、持久层设计等。一切设计以具体项目的具体背包物品需求为准。



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏