Unity3D玩家库存存读异常:加载后库存为空问题求助
问题分析与修复方案
看起来你遇到的核心问题出在库存数据的保存逻辑上,而且还有几个序列化相关的小坑需要填上。让我一步步帮你理清并修复:
1. 致命错误:InventoryData构造函数的赋值完全颠倒了
你在InventoryData的构造函数里,把空的items、itemAmounts字段赋值给了传入的inv对象,而不是把inv里的真实数据保存到InventoryData中。这直接导致你保存的文件里根本没有任何物品数据,加载自然返回空数组。
修复代码:
修改Inventory类里的InventoryData构造函数,把赋值方向反过来,并且去掉不需要序列化的UI组件(这些Unity组件无法被BinaryFormatter正确序列化):
[Serializable] public class InventoryData { // 只保存核心数据:物品数组和数量数组,UI组件不需要序列化 public int[] itemAmounts; public Item[] items; public InventoryData(Inventory inv){ // 初始化数组长度 items = new Item[Inventory.numItemSlots]; itemAmounts = new int[Inventory.numItemSlots]; // 把Inventory实例的数据复制到InventoryData中 for (int i = 0; i < Inventory.numItemSlots; i++) { items[i] = inv.items[i]; itemAmounts[i] = inv.itemAmounts[i]; // 删掉UI组件的赋值,这些属于视图层,不需要持久化 } } }
2. 必要前提:确保Item类可序列化
你的Item类必须添加[Serializable]属性,否则BinaryFormatter无法序列化它。如果Item是ScriptableObject,也要记得标记:
[Serializable] public class Item { public Sprite itemImage; public string itemName; // 你的其他物品字段... }
3. 加载后手动同步UI显示
直接赋值inv.items = loadedItems不会自动刷新UI,因为UI的更新逻辑只在AddItem里触发。你需要在加载后手动遍历数组更新UI:
修改Player的Load方法:
public void Load(){ Debug.Log ("Loading data (player / inventory)"); float[] loadedStats = SaveLoadManager.LoadPlayer (); Inventory.InventoryData loadedInvData = SaveLoadInventory.LoadInventoryData(); if(loadedInvData != null){ // 赋值核心数据 inv.items = loadedInvData.items; inv.itemAmounts = loadedInvData.itemAmounts; // 手动刷新UI for(int i = 0; i < Inventory.numItemSlots; i++){ if(inv.items[i] != null){ inv.itemImages[i].sprite = inv.items[i].itemImage; inv.itemImages[i].enabled = true; inv.itemAmountsText[i].text = inv.itemAmounts[i].ToString(); } else { inv.itemImages[i].enabled = false; inv.itemAmountsText[i].text = ""; } } } // 处理player stats的逻辑... }
同步修改SaveLoadInventory的Load方法:
让它返回完整的InventoryData,而不是只返回items,这样能同时加载物品数量:
public static Inventory.InventoryData LoadInventoryData(){ string savePath = Application.persistentDataPath + "/saves/player_inventory.inv"; if (File.Exists(savePath)) { BinaryFormatter bf = new BinaryFormatter (); using(FileStream stream = new FileStream(savePath, FileMode.Open)){ Inventory.InventoryData data = bf.Deserialize (stream) as Inventory.InventoryData; return data; } } else { return null; } }
4. 优化保存逻辑(可选)
你当前的保存逻辑每次都会创建新文件(player1.inv、player2.inv...),如果想覆盖最新存档而不是累积文件,可以修改SaveInventory方法用固定文件名:
public static void SaveInventory(Inventory inv){ BinaryFormatter bf = new BinaryFormatter(); string saveDir = Application.persistentDataPath + "/saves"; Directory.CreateDirectory(saveDir); string savePath = saveDir + "/player_inventory.inv"; // 固定文件名 Inventory.InventoryData data = new Inventory.InventoryData(inv); // 使用using自动关闭流,更安全 using(FileStream stream = new FileStream(savePath, FileMode.Create)){ bf.Serialize(stream, data); } }
做完这些修改后,再测试一下保存和加载流程:保存后检查存档文件是否存在,加载时确认loadedInvData.items和itemAmounts有数据,UI也能正确显示物品。
内容的提问来源于stack exchange,提问作者Kith M.
相关产品推荐
相关产品推荐

