(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 中序列化的变量类型。您不能直接序列化 Image
和 Text
组件,因为它们是 UnityEngine.Object
类型。对于 Image
组件,保存 Image
组件正在使用的 Sprite 的路径。对于 Text
组件,保存保存文本本身的 .text
属性 的值。
如果要为 Image
或 Text
组件序列化多个 属性,最好创建一个新的可序列化 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 了解更多信息。
每当通过播放器脚本保存或加载时,库存两边总是空白,我无法弄清楚问题出在哪里。库存使用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 中序列化的变量类型。您不能直接序列化 Image
和 Text
组件,因为它们是 UnityEngine.Object
类型。对于 Image
组件,保存 Image
组件正在使用的 Sprite 的路径。对于 Text
组件,保存保存文本本身的 .text
属性 的值。
如果要为 Image
或 Text
组件序列化多个 属性,最好创建一个新的可序列化 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。请参阅