在原本的 Inventory 的基础上,我发现一个问题,每当我需要列出一个新的列表的时候,我都需要创建一个新的 list 和 dectionary 在 Inventory 的每个方法中重新注册一遍,这太麻烦了,违背了低耦合性的原则,所以我对 inventory 重新进行了整理。

我创建了 IInventoryCategory 接口来对 Inventory 中常用的方法进行了抽象管理

IInventoryCategory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface IInventoryCategory

{

    ItemType GetItemType();

    void AddItem(ItemData item);

    void RemoveItem(ItemData item);

    void UpdateUI();

    void UpdateSelectedItem(ItemData selectedItem);

}

然后创建一个 InventoryCategory 用以管理大的类别

InventoryCategory.cs
1
2
3
4
5
6
7
8
9
private List<InventoryItem> items = new List<InventoryItem>();
    private Dictionary<ItemData, InventoryItem> itemDictionary = new Dictionary<ItemData, InventoryItem>();
    private UI_ItemSlot[] uiSlots;
    public InventoryCategory(UI_ItemSlot[] slots)
    {
        uiSlots = slots;
    }

    public ItemType GetItemType() => items.Count > 0 ? items[0].data.itemType : ItemType.None;

同时将一些方法进行重写

  • AddItem
    AddItem
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 添加新物品到分类中
    public virtual void AddItem(ItemData item)
    {
    // 检查物品是否已经存在于字典中
    if (!itemDictionary.TryGetValue(item, out InventoryItem existingItem))
    {
    // 如果物品不存在,创建一个新的 InventoryItem 并添加到列表和字典中
    InventoryItem newItem = new InventoryItem(item);
    items.Add(newItem);
    itemDictionary[item] = newItem;
    }
    else
    {
    // 如果物品已存在,则增加其堆叠数量
    existingItem.AddStack();
    }

    // 更新 UI 以反映最新的物品状态
    UpdateUI();
    }
  • RemoveItem
    RemoveItem
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // 从分类中移除物品
    public virtual void RemoveItem(ItemData item)
    {
    // 检查物品是否存在于字典中
    if (itemDictionary.TryGetValue(item, out InventoryItem existingItem))
    {
    if (existingItem.stackSize > 1)
    {
    // 如果物品堆叠数量大于 1,减少堆叠数量
    existingItem.RemoveStack();
    }
    else
    {
    // 如果堆叠数量为 1,移除物品
    items.Remove(existingItem);
    itemDictionary.Remove(item);
    }
    }

    // 更新 UI 以反映最新的物品状态
    UpdateUI();
    }
  • UpdateUI
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 更新 UI 槽位以显示当前的物品状态
    public virtual void UpdateUI()
    {
    // 清空所有 UI 槽位
    foreach (var slot in uiSlots)
    slot.CleanUpSlot();

    // 将当前的物品更新到槽位中
    for (int i = 0; i < items.Count && i < uiSlots.Length; i++)
    {
    uiSlots[i].UpdateSlot(items[i]);
    }
    }
  • UpdateSelectedItem
    UpdateSelectedItem
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 更新选中物品的状态
    public void UpdateSelectedItem(ItemData selectedItem)
    {
    // 遍历所有物品,更新它们的选中状态
    foreach (var item in items)
    {
    // 如果物品是选中的,则标记为选中,否则取消选中
    item.data.isSelect = item.data == selectedItem;
    }
    }

由于我需要单独列出 Equipment 下的小分类:Book 和 Weapon
所以我需要再创建一个类来对 Equipment 中的小分类进行单独的筛选以及其他操作

EquipmentCategory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
// 管理装备类型物品的分类
public class EquipmentCategory : MonoBehaviour, IInventoryCategory
{
// 每种装备类型与其物品列表的映射
private Dictionary<EquipmentType, List<InventoryItem>> typeToItems;

// 每种装备类型与其 UI 槽位数组的映射
private Dictionary<EquipmentType, UI_ItemSlot[]> typeToUISlots;

// 构造函数,用于初始化装备分类
public EquipmentCategory(Dictionary<EquipmentType, UI_ItemSlot[]> slotsMapping)
{
// 初始化字典
typeToItems = new Dictionary<EquipmentType, List<InventoryItem>>();
typeToUISlots = slotsMapping;

// 为每种装备类型创建空的物品列表
foreach (var type in typeToUISlots.Keys)
{
typeToItems[type] = new List<InventoryItem>();
}
}

// 返回此分类的物品类型
public ItemType GetItemType()
{
return ItemType.Equipment;
}

// 添加物品到分类中
public void AddItem(ItemData item)
{
// 确保物品是装备类型
if (item is ItemData_Equipment equipment)
{
var type = equipment.equipmentType;

// 获取该类型的物品列表
var items = typeToItems[type];

// 检查是否已经存在该物品
var existingItem = items.FirstOrDefault(i => i.data == item);
if (existingItem != null)
{
// 如果已存在,增加堆叠数量
existingItem.AddStack();
}
else
{
// 如果不存在,添加新的物品
var newItem = new InventoryItem(item);
items.Add(newItem);
}

// 更新对应类型的 UI
UpdateEquipmentSlots(type);
}
}

// 从分类中移除物品
public void RemoveItem(ItemData item)
{
// 确保物品是装备类型
if (item is ItemData_Equipment equipment)
{
var type = equipment.equipmentType;

// 获取该类型的物品列表
var items = typeToItems[type];

// 检查是否存在该物品
var existingItem = items.FirstOrDefault(i => i.data == item);
if (existingItem != null)
{
if (existingItem.stackSize > 1)
{
// 如果堆叠数量大于 1,则减少数量
existingItem.RemoveStack();
}
else
{
// 如果堆叠数量为 1,则完全移除
items.Remove(existingItem);
}

// 更新对应类型的 UI
UpdateEquipmentSlots(type);
}
}
}
//...以及其他方法
}

然后在 Inventory 中统一注册管理这些 Category

Inventory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void InitializeCategories()
{
equipment = new List<InventoryItem>();
equipmentDictionary = new Dictionary<ItemData_Equipment, InventoryItem>();
// 获取 UI 格子组件
inventoryItemSlot = inventorySlotParent.GetComponentsInChildren<UI_ItemSlot>();
stashItemSlot = stashSlotParent.GetComponentsInChildren<UI_ItemSlot>();
equipmentSlot = equpmentSlotParent.GetComponentsInChildren<UI_EquipmentSlot>();
bookSlot = bookSlotParent.GetComponentsInChildren<UI_ItemSlot>();
weaponSlot = weaponSlotParent.GetComponentsInChildren<UI_WeaponSlot>();
// 初始化每种装备类型对应的 UI
equipmentSlotsMapping = new Dictionary<EquipmentType, UI_ItemSlot[]>
{
{ EquipmentType.Book, bookSlot },
{ EquipmentType.Weapon, weaponSlot },
// { EquipmentType.Armor, armorSlots }
};
// 将映射传递给 EquipmentCategory
var equipmentCategory = new EquipmentCategory(equipmentSlotsMapping);
categories = new Dictionary<ItemType, IInventoryCategory>
{
{ ItemType.Equipment, equipmentCategory },
{ ItemType.Material, new InventoryCategory(stashItemSlot) }
};

}

随后就可以逐一优化方法,有新的列表加入的时候就不再需要全部注册一遍方法了
以 AddItem 为例
AddItem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public void AddItem(ItemData _item)
    {
        if (_item == null)
        {
            Debug.LogWarning("Cannot add a null item to inventory.");
            return;
        }
        // 根据 ItemType 找到对应的分类
        if (categories.TryGetValue(_item.itemType, out IInventoryCategory category))
        {
            // 如果是 Equipment 类型,需要进一步处理
            if (_item is ItemData_Equipment equipment)
            {
                // 针对 Equipment 类型,调用分类管理的方法
                var equipmentCategory = category as EquipmentCategory;
                equipmentCategory?.AddItem(equipment);
            }
            else
            {
                // 针对非 Equipment 类型(如 Material),直接添加
                category.AddItem(_item);
            }
        }
        else
        {
            Debug.LogWarning($"No category found for ItemType {_item.itemType}. Check your category setup.");
        }
    }