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

Unity3D问题:物品已在Inventory中找到,但GetItem()仍返回null

问题原因与解决方案

核心问题

你的Item类继承了MonoBehaviour,但在拾取物品时用new Item(itemName, itemPrefab)创建实例——这是完全错误的。Unity中的MonoBehaviour组件不能通过new关键字实例化,这样创建的对象没有绑定到任何GameObject,属于Unity生命周期外的无效实例。虽然它的getName()方法能返回正确值,但后续引用时会被判定为null,这就是你看到日志同时输出“Apple found in inventory”和“Apple is null”的原因。

另外,Inventory类的Update方法每帧都订阅InventoryUpdated事件,会导致事件被重复订阅,每次触发时UpdateInventoryDisplay会执行多次,也需要修复。

分步解决方案

1. 将Item改为普通数据类

把Item从MonoBehaviour组件改为纯数据类,因为物品的基础数据不需要依赖Unity的组件生命周期:

public class Item
{
    public string itemName;
    public GameObject itemPrefab;

    public Item(string name, GameObject prefab)
    {
        itemName = name;
        itemPrefab = prefab;
    }

    public override bool Equals(object obj)
    {
        if (obj is Item other)
        {
            return itemName.Equals(other.itemName);
        }
        return false;
    }

    public override int GetHashCode()
    {
        return itemName.GetHashCode();
    }

    public string getName()
    {
        return itemName;
    }
}

2. 创建单独的拾取逻辑组件

新建一个ItemPickup类,负责处理物品的显示、旋转和拾取逻辑,挂载在物品的GameObject上:

public class ItemPickup : MonoBehaviour
{
    public Item itemData; // 在Inspector面板中赋值对应的Item数据对象

    void Update()
    {
        transform.Rotate(0, 0.25f, 0, Space.Self);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            Inventory inventory = other.GetComponent<Inventory>();
            if (inventory != null)
            {
                // 传入有效的Item实例
                inventory.Add(itemData);
                Destroy(gameObject);
            }
        }
    }
}

3. 修复Inventory的事件订阅问题

把InventoryUpdated事件的订阅移到Start方法中,避免每帧重复订阅:

public class Inventory : MonoBehaviour
{
    public Dictionary<Item, int> inventory = new Dictionary<Item, int>();
    public TextMeshProUGUI inventoryText;
    public static event Action InventoryUpdated;

    void Start()
    {
        // 仅订阅一次事件
        InventoryUpdated += UpdateInventoryDisplay;
    }

    void Update()
    {
        UpdateInventoryDisplay();
    }

    private void UpdateInventoryDisplay()
    {
        inventoryText.text = "";

        foreach (var item in inventory)
        {
            inventoryText.text += $"{item.Key.getName()}: {item.Value}\n";
        }
    }
    
    public void Add(Item item){
        if (inventory.ContainsKey(item)){
            inventory[item] += 1;
        }
        else {
            inventory.Add(item, 1);
        }
        InventoryUpdated?.Invoke();
    }

    public void Use(Item item, int amount){
        if (inventory.ContainsKey(item)){
            inventory[item] -= amount;
            if (inventory[item] <= 0){
                inventory.Remove(item);
            }
        }
        InventoryUpdated?.Invoke();
    }

    public Item GetItem(string key)
    {
        foreach (var kvp in inventory)
        {
            Item item = kvp.Key;
            if (item.getName().Equals(key)){
                Debug.Log(item.getName() + " found in inventory");
                return item;
            }
        }
        Debug.Log(key + " not found");
        return null;
    }
}

4. 调整CookingSystem(无需修改代码)

现在GetItem方法返回的是有效的Item实例,CookingSystem中的判断会正常工作,不会再输出“Apple is null”。

验证方法

  1. 在Unity中创建一个普通的Item对象,赋值给ItemPickup的itemData字段。
  2. 运行游戏,拾取苹果后,日志只会输出“Apple found in inventory”,不会再出现“Apple is null”的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:43:10