保存列表<GameObject>并统一加载
Save List<GameObject> and load in unity
所以我有这个
List<GameObject> character;
里面有我想在游戏中随机生成的所有角色的数据。在初始游戏中,我们只有一个数据,即此列表中的一个 GameObject。当我从商店购买角色时,他们会被添加到名为“角色”的列表中。所有这些现在都工作正常。问题是当我在购买角色后退出游戏并再次播放时,这些购买没有被保存。我想知道一种保存和加载此 list<GameObject> characters
的方法。我试过 PlayerPrefs
但它似乎没有执行 lists
的保存,这是我知道如何统一保存的唯一方法。对代码的任何帮助。我已经看到字符串定界符(如果我发音正确的话)可以完成这项工作。但不知道它会做什么以及如何做任何人都可以帮助我。谢谢。
更新问题
这是我的商店脚本代码:
[System.Serializable] public class ShopItem
{
public Sprite CharacterImage;
public GameObject charactersModel;
public int Price;
public bool isPurchased = false;
}
public List<ShopItem> ShopItemsList;
[Header("Panel Holders")]
[SerializeField] GameObject MainMenu;
[SerializeField] GameObject SettingsHolder;
[SerializeField] GameObject ShopPanel;
[Space]
[Header("Item Template & Display")]
GameObject ItemTemplate;
GameObject g;
[SerializeField] Transform ShopScrollView;
Button buyBtn;
//String Delimiter for Characters is "/"
public char mCharacterDemiliter = '/';
GameObject getGameManager;
GameManager GameManagerRef;
public string mPurchasedCharaters = string.Empty;
public string[] mPurchasesCharacterList;
private void Start()
{
getGameManager = GameObject.Find("GameManager");
GameManagerRef = getGameManager.GetComponent<GameManager>();
ItemTemplate = ShopScrollView.GetChild(0).gameObject;
var length = ShopItemsList.Count;
for (int i = 0; i < length; i++)
{
g = Instantiate(ItemTemplate, ShopScrollView);
g.transform.GetChild(0).GetComponent<Image>().sprite = ShopItemsList[i].CharacterImage;
g.transform.GetChild(1).GetComponentInChildren<TextMeshProUGUI>().text = ShopItemsList[i].Price.ToString();
buyBtn = g.transform.GetChild(2).GetComponent<Button>();
if (ShopItemsList[i].isPurchased)
{
DisableBuyButton();
}
buyBtn.AddEventListener(i, OnShopItemBtnClicked);
}
Destroy(ItemTemplate);
}
private void OnEnable()
{
//GameManagerRef.isCharacterPurchased = PlayerPrefs.GetString("SaveCharacterPurchaseData");
GameManagerRef.mPurchasedCharaters = PlayerPrefs.GetString("SavedCharacters");
mPurchasesCharacterList = mPurchasedCharaters.Split(mCharacterDemiliter);
foreach (var sub in mPurchasesCharacterList)
{
ShopItemsList[].isPurchased = true;
Debug.Log(int.Parse(sub));
DisableBuyButton();
}
}
public void DisableBuyButton()
{
buyBtn.interactable = false;
buyBtn.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = "PURCHASED";
//Destroy(buyBtn);
}
public void OpenShop()
{
MainMenu.SetActive(false);
SettingsHolder.SetActive(false);
ShopPanel.SetActive(true);
}
public void ReturnButton()
{
MainMenu.SetActive(true);
SettingsHolder.SetActive(true);
ShopPanel.SetActive(false);
}
int boolToInt(bool val)
{
if (val)
return 1;
else
return 0;
}
void OnShopItemBtnClicked(int itemIndex)
{
if (GameManagerRef.HasEnoughCoins(ShopItemsList[itemIndex].Price))
{
//purchase Item
GameManagerRef.UseCoins(ShopItemsList[itemIndex].Price);
ShopItemsList[itemIndex].isPurchased = true;
buyBtn = ShopScrollView.GetChild(itemIndex).GetChild(2).GetComponent<Button>();
GameManagerRef.character.Add(ShopItemsList[itemIndex].charactersModel);
DisableBuyButton();
#region "Save the purchased character"
GameManagerRef.mPurchasedCharaters = GameManagerRef.mPurchasedCharaters + GameManagerRef.mCharacterDemiliter + ShopItemsList[itemIndex].charactersModel.name;
PlayerPrefs.SetString("SavedCharacters", GameManagerRef.mPurchasedCharaters);
GameManagerRef.isCharacterPurchased = GameManagerRef.isCharacterPurchased + GameManagerRef.mCharacterDemiliter + ShopItemsList[itemIndex].isPurchased;
PlayerPrefs.SetString("SaveCharacterPurchaseData", GameManagerRef.isCharacterPurchased);
//PlayerPrefs.SetInt("SaveCharacterPurchaseData", boolToInt(ShopItemsList[itemIndex].isPurchased));
#endregion
}
else
{
Debug.Log("You dont have sufficient amount");
}
}
此处保存角色模型并将其加载回去可以正常使用播放器偏好设置。我让它工作了,但问题是一旦我买了东西,它就会改变购买。除非退出游戏并再次回来,否则很酷。它再次从购买变为购买。尝试保存字符串,否则我什至不知道它是否正确。请帮忙@dgates82.
参考我的GameManager
脚本因为我一直同时使用它们
public static GameManager Instance;
//Stores Coin Value throughout the game
/*[HideInInspector]*/ public int coin = 0;
//Retreive / Load Coin Value thats saved
int savedCoin;
//Get the LevelManager of that specific scene
[HideInInspector] public GameObject LevelManagerRef;
/*[HideInInspector]*/ public GameObject shopRef;
/*[HideInInspector]*/ public Shop storeShopScript;
public List<GameObject> character = new List<GameObject>();
[Space]
[Header("Save and load store Character Data")]
public string mPurchasedCharaters = string.Empty;
public string isCharacterPurchased = string.Empty;
public string[] mPurchasesCharacterList;
public string[] characterPurchasedList;
public char mCharacterDemiliter = '/';
void Awake()
{
//Loads the coin save Data
LoadCoinSaveData();
#region "Singleton Code"
//Checks to see if there is another gameManager instance and deletes that
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(this); //Singleton
return;
}
Destroy(this.gameObject);
#endregion
}
private void Start()
{
shopRef = FindInActiveObjectByName("ShopMenu");
storeShopScript = shopRef.GetComponent<Shop>();
PopulateCharacters();
//makePurchased();
}
#region "Populate SavedCharacters"
public void PopulateCharacters()
{
mPurchasedCharaters = PlayerPrefs.GetString("SavedCharacters");
if(mPurchasedCharaters == string.Empty)
{
mPurchasedCharaters = "Man";
PlayerPrefs.SetString("SavedCharacters", mPurchasedCharaters);
}
mPurchasesCharacterList = mPurchasedCharaters.Split(mCharacterDemiliter);
foreach (var sub in mPurchasesCharacterList)
{
GameObject loadedCharacter = Resources.Load(sub) as GameObject;
character.Add(loadedCharacter);
}
}
//public void makePurchased()
//{
// isCharacterPurchased = PlayerPrefs.GetString("SaveCharacterPurchaseData");
// characterPurchasedList = isCharacterPurchased.Split(mCharacterDemiliter);
// foreach (string characterSaved in characterPurchasedList)
// {
// for (int i = 0; i <= storeShopScript.ShopItemsList.Count; i++)
// {
// if ()
// {
// storeShopScript.ShopItemsList[i].isPurchased = Convert.ToBoolean(bool.Parse(characterSaved));
// }
// }
// }
//}
#endregion
private void LoadCoinSaveData()
{
savedCoin = PlayerPrefs.GetInt("SavedCoinValue");
coin = savedCoin;
}
//Reduce the coin value depending upon the amount
public void UseCoins(int amount)
{
coin -= amount;
}
//Use coins if enough coins are there?
public bool HasEnoughCoins(int amount)
{
return (coin >= amount);
}
GameObject FindInActiveObjectByName(string name)
{
Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
for (int i = 0; i < objs.Length; i++)
{
if (objs[i].hideFlags == HideFlags.None)
{
if (objs[i].name == name)
{
return objs[i].gameObject;
}
}
}
return null;
}
}
如评论中所述,您不能序列化 GameObjects,或任何从 MonoBehaviour 继承的东西。
所以我们需要先创建一个class,我们可以序列化它来存储一些相关数据,并用“可序列化”属性标记它。
[Serializable]
public class CharacterData // Do not inherit from MonoBehaviour here
{
public int Id;
public string Name;
public int HitPoints;
public int AttackDamage;
}
并且您的角色游戏对象将使用此数据
public Character : MonoBehaviour
{
public CharacterData Data;
private int hitPoints;
// Retrieve data from CharacterData for local use
void Awake()
{
hitPoints = Data.HitPoints;
}
}
然后我们将创建另一个可序列化的 class 来保存我们所有的各种保存数据,非常有创意的命名... SaveData,它有一个 CharacterData 列表作为字段。
[Serializable]
public class SaveData // Do not inherit from MonoBehaviour here
{
public List<CharacterData> Characters;
}
现在您可以序列化和反序列化您的 SaveData 并将其存储在任何您想要的地方
public class SaveManager : MonoBehavior
{
public void Save(SaveData data)
{
// Serialize to json
var jsonData = JsonUtility.ToJson(data);
// Now save the json locally, to GPGS, etc. as you choose
}
public void Load()
{
// Retrieve json data from storage of your choice
var jsonData = somehow get from storage
// Then deserialize it back to an object
var saveData = JsonUtility.FromJson<SaveData>(jsonData);
// And then apply it to your characters
// For example, maybe you instantiate your prefabs and then add the character data
foreach (var characterData in saveData.Characters)
{
var spawnPoint = // need a spawn point
var characterPrefab = // need a prefab to assign
var character = Instantiate(characterPrefab, spawnPoint);
// Assign the saved character data to the new game object
character.CharacterData = characterData;
}
}
}
所以我有这个
List<GameObject> character;
里面有我想在游戏中随机生成的所有角色的数据。在初始游戏中,我们只有一个数据,即此列表中的一个 GameObject。当我从商店购买角色时,他们会被添加到名为“角色”的列表中。所有这些现在都工作正常。问题是当我在购买角色后退出游戏并再次播放时,这些购买没有被保存。我想知道一种保存和加载此 list<GameObject> characters
的方法。我试过 PlayerPrefs
但它似乎没有执行 lists
的保存,这是我知道如何统一保存的唯一方法。对代码的任何帮助。我已经看到字符串定界符(如果我发音正确的话)可以完成这项工作。但不知道它会做什么以及如何做任何人都可以帮助我。谢谢。
更新问题 这是我的商店脚本代码:
[System.Serializable] public class ShopItem
{
public Sprite CharacterImage;
public GameObject charactersModel;
public int Price;
public bool isPurchased = false;
}
public List<ShopItem> ShopItemsList;
[Header("Panel Holders")]
[SerializeField] GameObject MainMenu;
[SerializeField] GameObject SettingsHolder;
[SerializeField] GameObject ShopPanel;
[Space]
[Header("Item Template & Display")]
GameObject ItemTemplate;
GameObject g;
[SerializeField] Transform ShopScrollView;
Button buyBtn;
//String Delimiter for Characters is "/"
public char mCharacterDemiliter = '/';
GameObject getGameManager;
GameManager GameManagerRef;
public string mPurchasedCharaters = string.Empty;
public string[] mPurchasesCharacterList;
private void Start()
{
getGameManager = GameObject.Find("GameManager");
GameManagerRef = getGameManager.GetComponent<GameManager>();
ItemTemplate = ShopScrollView.GetChild(0).gameObject;
var length = ShopItemsList.Count;
for (int i = 0; i < length; i++)
{
g = Instantiate(ItemTemplate, ShopScrollView);
g.transform.GetChild(0).GetComponent<Image>().sprite = ShopItemsList[i].CharacterImage;
g.transform.GetChild(1).GetComponentInChildren<TextMeshProUGUI>().text = ShopItemsList[i].Price.ToString();
buyBtn = g.transform.GetChild(2).GetComponent<Button>();
if (ShopItemsList[i].isPurchased)
{
DisableBuyButton();
}
buyBtn.AddEventListener(i, OnShopItemBtnClicked);
}
Destroy(ItemTemplate);
}
private void OnEnable()
{
//GameManagerRef.isCharacterPurchased = PlayerPrefs.GetString("SaveCharacterPurchaseData");
GameManagerRef.mPurchasedCharaters = PlayerPrefs.GetString("SavedCharacters");
mPurchasesCharacterList = mPurchasedCharaters.Split(mCharacterDemiliter);
foreach (var sub in mPurchasesCharacterList)
{
ShopItemsList[].isPurchased = true;
Debug.Log(int.Parse(sub));
DisableBuyButton();
}
}
public void DisableBuyButton()
{
buyBtn.interactable = false;
buyBtn.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = "PURCHASED";
//Destroy(buyBtn);
}
public void OpenShop()
{
MainMenu.SetActive(false);
SettingsHolder.SetActive(false);
ShopPanel.SetActive(true);
}
public void ReturnButton()
{
MainMenu.SetActive(true);
SettingsHolder.SetActive(true);
ShopPanel.SetActive(false);
}
int boolToInt(bool val)
{
if (val)
return 1;
else
return 0;
}
void OnShopItemBtnClicked(int itemIndex)
{
if (GameManagerRef.HasEnoughCoins(ShopItemsList[itemIndex].Price))
{
//purchase Item
GameManagerRef.UseCoins(ShopItemsList[itemIndex].Price);
ShopItemsList[itemIndex].isPurchased = true;
buyBtn = ShopScrollView.GetChild(itemIndex).GetChild(2).GetComponent<Button>();
GameManagerRef.character.Add(ShopItemsList[itemIndex].charactersModel);
DisableBuyButton();
#region "Save the purchased character"
GameManagerRef.mPurchasedCharaters = GameManagerRef.mPurchasedCharaters + GameManagerRef.mCharacterDemiliter + ShopItemsList[itemIndex].charactersModel.name;
PlayerPrefs.SetString("SavedCharacters", GameManagerRef.mPurchasedCharaters);
GameManagerRef.isCharacterPurchased = GameManagerRef.isCharacterPurchased + GameManagerRef.mCharacterDemiliter + ShopItemsList[itemIndex].isPurchased;
PlayerPrefs.SetString("SaveCharacterPurchaseData", GameManagerRef.isCharacterPurchased);
//PlayerPrefs.SetInt("SaveCharacterPurchaseData", boolToInt(ShopItemsList[itemIndex].isPurchased));
#endregion
}
else
{
Debug.Log("You dont have sufficient amount");
}
}
此处保存角色模型并将其加载回去可以正常使用播放器偏好设置。我让它工作了,但问题是一旦我买了东西,它就会改变购买。除非退出游戏并再次回来,否则很酷。它再次从购买变为购买。尝试保存字符串,否则我什至不知道它是否正确。请帮忙@dgates82.
参考我的GameManager
脚本因为我一直同时使用它们
public static GameManager Instance;
//Stores Coin Value throughout the game
/*[HideInInspector]*/ public int coin = 0;
//Retreive / Load Coin Value thats saved
int savedCoin;
//Get the LevelManager of that specific scene
[HideInInspector] public GameObject LevelManagerRef;
/*[HideInInspector]*/ public GameObject shopRef;
/*[HideInInspector]*/ public Shop storeShopScript;
public List<GameObject> character = new List<GameObject>();
[Space]
[Header("Save and load store Character Data")]
public string mPurchasedCharaters = string.Empty;
public string isCharacterPurchased = string.Empty;
public string[] mPurchasesCharacterList;
public string[] characterPurchasedList;
public char mCharacterDemiliter = '/';
void Awake()
{
//Loads the coin save Data
LoadCoinSaveData();
#region "Singleton Code"
//Checks to see if there is another gameManager instance and deletes that
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(this); //Singleton
return;
}
Destroy(this.gameObject);
#endregion
}
private void Start()
{
shopRef = FindInActiveObjectByName("ShopMenu");
storeShopScript = shopRef.GetComponent<Shop>();
PopulateCharacters();
//makePurchased();
}
#region "Populate SavedCharacters"
public void PopulateCharacters()
{
mPurchasedCharaters = PlayerPrefs.GetString("SavedCharacters");
if(mPurchasedCharaters == string.Empty)
{
mPurchasedCharaters = "Man";
PlayerPrefs.SetString("SavedCharacters", mPurchasedCharaters);
}
mPurchasesCharacterList = mPurchasedCharaters.Split(mCharacterDemiliter);
foreach (var sub in mPurchasesCharacterList)
{
GameObject loadedCharacter = Resources.Load(sub) as GameObject;
character.Add(loadedCharacter);
}
}
//public void makePurchased()
//{
// isCharacterPurchased = PlayerPrefs.GetString("SaveCharacterPurchaseData");
// characterPurchasedList = isCharacterPurchased.Split(mCharacterDemiliter);
// foreach (string characterSaved in characterPurchasedList)
// {
// for (int i = 0; i <= storeShopScript.ShopItemsList.Count; i++)
// {
// if ()
// {
// storeShopScript.ShopItemsList[i].isPurchased = Convert.ToBoolean(bool.Parse(characterSaved));
// }
// }
// }
//}
#endregion
private void LoadCoinSaveData()
{
savedCoin = PlayerPrefs.GetInt("SavedCoinValue");
coin = savedCoin;
}
//Reduce the coin value depending upon the amount
public void UseCoins(int amount)
{
coin -= amount;
}
//Use coins if enough coins are there?
public bool HasEnoughCoins(int amount)
{
return (coin >= amount);
}
GameObject FindInActiveObjectByName(string name)
{
Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
for (int i = 0; i < objs.Length; i++)
{
if (objs[i].hideFlags == HideFlags.None)
{
if (objs[i].name == name)
{
return objs[i].gameObject;
}
}
}
return null;
}
}
如评论中所述,您不能序列化 GameObjects,或任何从 MonoBehaviour 继承的东西。
所以我们需要先创建一个class,我们可以序列化它来存储一些相关数据,并用“可序列化”属性标记它。
[Serializable]
public class CharacterData // Do not inherit from MonoBehaviour here
{
public int Id;
public string Name;
public int HitPoints;
public int AttackDamage;
}
并且您的角色游戏对象将使用此数据
public Character : MonoBehaviour
{
public CharacterData Data;
private int hitPoints;
// Retrieve data from CharacterData for local use
void Awake()
{
hitPoints = Data.HitPoints;
}
}
然后我们将创建另一个可序列化的 class 来保存我们所有的各种保存数据,非常有创意的命名... SaveData,它有一个 CharacterData 列表作为字段。
[Serializable]
public class SaveData // Do not inherit from MonoBehaviour here
{
public List<CharacterData> Characters;
}
现在您可以序列化和反序列化您的 SaveData 并将其存储在任何您想要的地方
public class SaveManager : MonoBehavior
{
public void Save(SaveData data)
{
// Serialize to json
var jsonData = JsonUtility.ToJson(data);
// Now save the json locally, to GPGS, etc. as you choose
}
public void Load()
{
// Retrieve json data from storage of your choice
var jsonData = somehow get from storage
// Then deserialize it back to an object
var saveData = JsonUtility.FromJson<SaveData>(jsonData);
// And then apply it to your characters
// For example, maybe you instantiate your prefabs and then add the character data
foreach (var characterData in saveData.Characters)
{
var spawnPoint = // need a spawn point
var characterPrefab = // need a prefab to assign
var character = Instantiate(characterPrefab, spawnPoint);
// Assign the saved character data to the new game object
character.CharacterData = characterData;
}
}
}