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

Unity场景切换时Inventory报MissingReferenceException故障求助

解决Unity Inventory系统跨场景MissingReferenceException及物品持久化问题

问题根源

场景切换时,旧场景里的UI元素(比如InventoryItemUI绑定的Image组件)会被销毁,但你的InventoryController如果是跨场景保留的单例,大概率还攥着旧场景的UI引用——调用ResetData时自然会触发已销毁对象的访问异常。注释掉初始物品添加逻辑后,没触发对旧UI的操作,所以错误消失,但同时也丢了物品跨场景保存的能力。

解决方案

1. 修复UI引用丢失

  • 场景加载后重新绑定UI
    给InventoryController加个场景加载完成的监听,每次切场景后重新获取当前场景的UI实例,替换掉旧的销毁引用:

    private void OnEnable()
    {
        SceneManager.sceneLoaded += OnSceneLoaded;
    }
    
    private void OnDisable()
    {
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }
    
    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        // 重新查找并初始化当前场景的物品槽UI
        RefreshInventoryUIReferences();
    }
    

    其中RefreshInventoryUIReferences()负责遍历当前场景的InventoryItemUI组件,重新绑定内部的Image、文本等引用。

  • 给ResetData加安全判断
    修改InventoryItemUI的ResetData方法,先检查组件是否存活,再执行逻辑:

    public void ResetData()
    {
        if (this == null || !gameObject.activeInHierarchy)
            return;
    
        // 原有清空逻辑
        itemImage.sprite = null;
        itemImage.enabled = false;
        countText.text = string.Empty;
    }
    

2. 实现物品跨场景持久化

  • 用单例存数据,别绑UI
    让InventoryController做跨场景不销毁的单例,把物品数据存在独立的列表里,不要依赖UI组件保存数据:
    public class InventoryController : MonoBehaviour
    {
        public static InventoryController Instance;
        public List<ItemData> inventoryItems = new List<ItemData>();
    
        private void Awake()
        {
            if (Instance == null)
            {
                Instance = this;
                DontDestroyOnLoad(gameObject);
            }
            else
            {
                Destroy(gameObject);
            }
        }
    
        // 添加物品只操作数据列表
        public void AddItem(ItemData item)
        {
            inventoryItems.Add(item);
            // 通知当前场景的UI更新
            SyncInventoryToUI();
        }
    
        // 把数据同步到当前场景的UI上
        private void SyncInventoryToUI()
        {
            var currentSlots = FindObjectsOfType<InventoryItemUI>();
            for (int i = 0; i < currentSlots.Length; i++)
            {
                if (i < inventoryItems.Count)
                {
                    currentSlots[i].SetItemData(inventoryItems[i]);
                }
                else
                {
                    currentSlots[i].ResetData();
                }
            }
        }
    }
    
  • 调整初始物品添加逻辑
    原来的初始物品循环,直接往inventoryItems列表里加数据就行,不要直接操作UI。等场景加载完成后,调用SyncInventoryToUI()把数据渲染到当前场景的UI上。

3. 额外提醒

  • 别给InventoryItemUI设置DontDestroyOnLoad,UI是属于场景的,切场景时该销毁就销毁,新场景重新生成就行。
  • 测试时重点看两点:切场景后inventoryItems列表数据是否保留,UI组件是不是当前场景的新实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 13:32:31