(Unity3D) Saving/Loading 玩家库存

(Unity3D) Saving/Loading Player Inventory

每当通过播放器脚本保存或加载时,库存两边总是空白,我无法弄清楚问题出在哪里。库存使用Unity的中级库存教程中使用的相同系统,它工作正常,但加载时库存总是空白。

玩家

public void Save(){
    Debug.Log ("Saving data (player / inventory)");

    SaveLoadManager.SavePlayer (this); //works fine
    SaveLoadInventory.SaveInventory (inv); //where the issue is
}
public void Load(){
    Debug.Log ("Loading data (player / inventory)");

    float[] loadedStats = SaveLoadManager.LoadPlayer (); //works fine
    Item[] loadedItems = SaveLoadInventory.LoadInventory (); //comes up empty

    inv.items = loadedItems; //try to set the referenced Inventory script array of items equal to the loaded items

    //loadedStats[...] are set to player values and all works good
}

库存

public class Inventory : MonoBehaviour {

public Image[] itemImages = new Image[numItemSlots];
public Text[] itemAmountsText = new Text[numItemSlots];
public int[] itemAmounts = new int[numItemSlots];
public Item[] items = new Item[numItemSlots];

public const int numItemSlots = 40;

public void AddItem(Item itemToAdd){
    for (int i = 0; i < items.Length; i++) {
        if(items [i] == itemToAdd){
            if (itemAmounts [i] <= 99) {
                itemAmounts [i]++;
            } else {
                items [i] = itemToAdd;
                itemImages [i].sprite = itemToAdd.itemImage;
                itemImages [i].enabled = true;
            }
            itemAmountsText [i].text = itemAmounts [i] + "";
            return;
        } else if (items [i] == null) {
            itemAmounts [i]++;
            itemAmountsText [i].text = itemAmounts [i] + "";
            items [i] = itemToAdd;
            itemImages [i].sprite = itemToAdd.itemImage;
            itemImages [i].enabled = true;
            return;
        }
    }
}

public void RemoveItem(Item itemToRemove){
    for (int i = 0; i < items.Length; i++) {
        if (items [i] == itemToRemove) {
            items [i] = null;
            itemImages [i].sprite = null;
            itemImages [i].enabled = false;
            return;
        }
    }
}

public void ClearAllItems(){
    for (int i = 0; i < items.Length; i++) {
        items [i] = null;
        itemImages [i].sprite = null;
        itemImages [i].enabled = false;
        return;
    }
}

[Serializable]
public class InventoryData {
    public Image[] itemImages = new Image[numItemSlots];
    public Text[] itemAmountsText = new Text[numItemSlots];
    public int[] itemAmounts = new int[numItemSlots];
    public Item[] items;

    public InventoryData(Inventory inv){
        items = new Item[numItemSlots];

        for (int i = 0; i < items.Length; i++) {
            inv.items[i] = items[i];
            inv.itemAmounts[i] = itemAmounts[i];
            inv.itemAmountsText[i] = itemAmountsText[i];
            inv.itemImages[i] = itemImages[i];
            }
        }
    }
}

保存加载清单

public static class SaveLoadInventory {

    public static void SaveInventory(Inventory inv){

    BinaryFormatter bf = new BinaryFormatter();
    var createdir = Directory.CreateDirectory(Application.persistentDataPath + "/saves");
    String dir = Application.persistentDataPath + "/saves";
    Inventory.InventoryData data = new Inventory.InventoryData (inv);

    DirectoryInfo dir_i = new DirectoryInfo(dir);
    FileInfo[] info = dir_i.GetFiles("*.inv");
    foreach (FileInfo f in info) {
        Debug.Log (f);
    }

    FileStream stream = new FileStream (dir + "/player" + (info.Length + 1) + ".inv", FileMode.Create);

    bf.Serialize (stream, data);
    stream.Close ();

}

    public static Item[] LoadInventory(){
    String dir = Application.persistentDataPath + "/saves";

    DirectoryInfo dir_i = new DirectoryInfo(dir);
    FileInfo[] info = dir_i.GetFiles("*.inv");
    foreach (FileInfo f in info) {
        Debug.Log (f);
    }

    if (info.Length >= 1) {

        BinaryFormatter bf = new BinaryFormatter ();
        var createdir = Directory.CreateDirectory(Application.persistentDataPath + "/saves");
        FileStream stream = new FileStream (dir + "/player" + (info.Length) + ".inv", FileMode.Open);
        Inventory.InventoryData data = bf.Deserialize (stream) as Inventory.InventoryData;

        stream.Close ();
        return data.items;
    } else {
        return null;
    }
}

老实说,我会为此尝试一些调试组合并自己弄清楚,但是这一切似乎太复杂了,我无法理解并且一直担心它永远不会起作用。如果您有任何帮助或建议,我们将不胜感激。

but the inventory is always blank when loading.

第一个问题是您要在 InventoryData class 中序列化的变量类型。您不能直接序列化 ImageText 组件,因为它们是 UnityEngine.Object 类型。对于 Image 组件,保存 Image 组件正在使用的 Sprite 的路径。对于 Text 组件,保存保存文本本身的 .text 属性 的值。

如果要为 ImageText 组件序列化多个 属性,最好创建一个新的可序列化 class/wrapper,它将保存要为 Image 组件序列化的重要数据和另一个要为 Text 组件序列化的重要数据。

例如,假设您想要序列化有关 Text 组件的信息,例如字体大小、实际文本和颜色,这里是一个简单的包装器示例:

[Serializable]
public class TextWrapper
{
    public int fontSize;
    public string text;
    public Color color;

    public TextWrapper(Text text)
    {

        //Get Text Info
        fontSize = text.fontSize;
        this.text = text.text;
        color = text.color;
    }
}

要序列化的 Text 组件:

public Text myText;

您可以从 Text 组件创建 TextWrapper 的新实例以序列化:

TextWrapper textWrapper = new TextWrapper(myText);

现在,您可以在问题中使用 BinaryFormatter 序列化它。您可以将 TextWrapper 变量放在 InventoryData class 中,这也应该序列化。

注意 TextWrapper 必须放在它自己的 .cs 文件中,否则 BinaryFormatter 可能会归档到 serialize/deserialize 它。如果您在使用 .. 时仍有问题,请使用 Json。请参阅 post 了解更多信息。