You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何实现可存储int、string、Sprite的物品清单?

问题分析与解决方案

核心问题

  1. 初始代码直接存储ItemData(ScriptableObject)实例,所有背包条目共享同一份SO数据,修改任一条目数量会影响原SO,且Inspector仅显示SO引用,无法直观查看每个条目的具体数据。
  2. 修改后的代码错误地使用new ItemData()创建ScriptableObject实例(Unity禁止直接new SO,必须通过ScriptableObject.CreateInstance),且创建的物品未添加到items列表,导致数据丢失。

正确实现方案

我们需要区分物品模板和背包物品实例:用ItemData SO存储物品的基础属性(名称、图标),再创建一个可序列化的普通类来存储背包中每个物品的实例数据(包含SO模板引用+数量),这样既复用SO的配置,又能独立管理每个背包条目的数量,同时让Inspector正常显示所有数据。

1. 定义物品模板与背包条目类

using System.Collections.Generic;
using UnityEngine;

// 物品模板:用ScriptableObject存储基础属性,可在Project窗口创建配置文件
[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item")]
public class ItemData : ScriptableObject
{
    public string itemName;
    public Sprite itemIcon;
    // 移除amountOfItem,因为数量是背包实例的属性,不是模板属性
}

// 背包条目:可序列化的普通类,存储每个物品的实例数据
[System.Serializable]
public class InventoryItem
{
    public ItemData itemTemplate; // 引用物品模板
    public int quantity; // 当前背包中该物品的数量
}

2. 修改Inventory脚本实现拾取逻辑

public class Inventory : MonoBehaviour
{
    public List<InventoryItem> items = new List<InventoryItem>();

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Item"))
        {
            // 从拾取物上获取物品配置
            PickupItem pickup = other.GetComponent<PickupItem>();
            if (pickup != null && pickup.itemTemplate != null)
            {
                AddItemToInventory(pickup.itemTemplate, pickup.quantity);
                Destroy(other.gameObject);
            }
        }
    }

    // 添加物品到背包:存在同类型则叠加数量,否则新增条目
    private void AddItemToInventory(ItemData itemTemplate, int addQuantity)
    {
        // 检查背包中是否已有该物品
        InventoryItem existingItem = items.Find(item => item.itemTemplate == itemTemplate);
        if (existingItem != null)
        {
            existingItem.quantity += addQuantity;
        }
        else
        {
            // 创建新的背包条目并添加到列表
            InventoryItem newItem = new InventoryItem();
            newItem.itemTemplate = itemTemplate;
            newItem.quantity = addQuantity;
            items.Add(newItem);
        }
    }
}

3. 新增PickupItem脚本挂载到拾取物上

using UnityEngine;

// 挂载在场景中的拾取物上,配置要拾取的物品模板和数量
public class PickupItem : MonoBehaviour
{
    public ItemData itemTemplate;
    public int quantity = 1; // 拾取该物品时获得的数量,默认为1
}

方案优势

  • 数据解耦:物品模板(SO)和背包实例数据分离,修改背包数量不会影响原SO配置。
  • Inspector可视化:List<InventoryItem>会在Inspector中展开显示每个条目的物品模板和数量,方便调试和编辑。
  • 扩展性强:后续添加物品消耗、堆叠上限等功能时,直接修改InventoryItem和AddItemToInventory逻辑即可。

为什么之前的代码出错

  • 直接存储SO实例:所有背包条目共享同一份SO数据,修改数量会同步到Project窗口中的SO文件,导致数据混乱。
  • 用new ItemData()创建SO:Unity中ScriptableObject必须通过ScriptableObject.CreateInstance<ItemData>()创建,直接new会导致对象无法被Unity正确管理,出现参数异常。

内容的提问来源于stack exchange,提问作者BeeCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:10:43