c# - 如何添加新数据并保留旧的现有数据
问题描述
我几乎完成了我的手机游戏的制作,并且我有一个使用此视频中显示的内容的 DATA 脚本。我有一个列表,其中包含玩家可以完成的不同挑战的值。我将如何更新游戏,以便在保留旧数据的同时添加更多挑战。
(挑战数据基本包含是否完成,距离完成还有多远)
我看过这个指南,但我不太明白。我是序列化的新手。
先感谢您 :)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
[System.Serializable]
public class XMLManager : MonoBehaviour {
public static XMLManager dataManagement;
public gameData data;
void Awake()
{
//File.Delete(Application.dataPath + "/StreamingFiles/XML/item_data.xml");
System.Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
dataManagement = this;
DontDestroyOnLoad(gameObject);
}
public void SaveData()
{
XmlSerializer serializer = new XmlSerializer(typeof(gameData));
System.Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
FileStream stream = new FileStream(Application.dataPath + "/StreamingFiles/XML/item_data.xml", FileMode.Create);
serializer.Serialize(stream, data);
stream.Close();
}
public void LoadData()
{
System.Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
if (File.Exists(Application.dataPath + "/StreamingFiles/XML/item_data.xml"))
{
XmlSerializer serializer = new XmlSerializer(typeof(gameData));
FileStream stream = new FileStream(Application.dataPath + "/StreamingFiles/XML/item_data.xml", FileMode.Open);
data = serializer.Deserialize(stream) as gameData;
stream.Close();
}
else
{
print("SaveData");
SaveData();
}
}
}
[System.Serializable]
public class gameData
{
public List<ChallengeStatus> Challenges;
public int HighScore;
public int CoinsCollected;
public List<bool> Unlocked;
public int GamesPlayed;
public int currentChallenge;
}
[System.Serializable]
public class ChallengeStatus
{
public int id;
public string title;
public int current;
public int max;
public int reward;
public bool completed;
public bool claimed;
}
解决方案
First you should have a look at Unity XML Serialization and use proper attributes. You don't totally need them (except maybe the [XmlRoot]
) but they let you customize your Xml file. If not provided Unity uses the variable names and uses sub-elements instead of attributes. However afaik this works only for primitives (int
, float
, string
, bool
, etc) and lists of them not for your own class ChallengeStatus
. So at least for the list of your class you have to provide attributes:
[System.Serializable]
[XmlRoot("GameData")]
public class GameData
{
[XmlArray("Challenges")]
[XmlArrayItem("ChallengeStatus)]
public List<ChallengeStatus> Challenges;
//...
}
Now I don't really understand why you need to keep the old XML file when saving a new one but if you want to keep the current file I would add an int FileCounter
.. ofcourse not in the same XML file ;) Might be e.g. via PlayerPrefs or a second simple text file only including the number or something similar.
Note it is better/saver to use Path.Combine for concatenate systempaths) - the overload taking an array of strings requires .Net4. Something like
private string FilePath
{
get
{
//TODO first load / read the FileCounter from somewhere
var paths = {
Application.dataPath,
"StreamingFiles",
"XML",
// here you get from somewhere and use that global FileCounter
string.Format("item_data_{0}.xml", FileCounter)};
return Path.Combine(paths);
}
}
Than you can increase that global FileCounter
everytime you save the file.
public void SaveData()
{
//TODO somehow increase the global value
// store to PlayerPrefs or write a new file or ...
FileCounter += 1;
System.Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
// better use the "using" keyword for streams
// use the FilePath field to get the filepath including the filecounter
using(FileStream stream = new FileStream(FilePath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(gameData))
serializer.Serialize(stream, data);
}
}
And read the file with the current FileCounter
without increasing it
public void LoadData()
{
System.Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
if (File.Exists(FilePath))
{
// better use a "using" block for streams
// use the FilePath field to get the filepath including the filecounter
using(FileStream stream = new FileStream(FilePath, FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(gameData));
data = serializer.Deserialize(stream) as gameData;
}
}
else
{
print("SaveData");
SaveData();
}
}
Hint 1:
As soon as you provide a constructor for your classes e.g.
public GameData(List<ChallengeStatus> challenges)
{
Challenges = challenges;
}
than you always have to also provide a default constructor (even if it does nothing)
public GameData(){ }
Hint 2:
You should always initialize your lists:
public class GameData
{
public List<ChallengeStatus> Challenges = new List≤ChallangeStatus>();
//...
public List<bool> Unlocked = new List<bool>();
//...
}
Hint 3:
Btw you don't need that [System.Serializable]
for XmlManager
since it inherits from MonoBehaviour
which already is serializable anyway.
推荐阅读
- entity-framework - 如何在实体框架中命名链接列
- android - android studio 构建崩溃
- python - 合并两个不同长度的数据帧(内连接)
- ios - .eml 文件未显示在 qlpreviewcontroller-swift 中
- excel - 尝试在自动复选框后自动在多列中添加日期
- python - 任何人都可以帮助我使用以下示例的正则表达式吗?
- r - R中case_when语句中的表达式
- javascript - vue.js 如何将类绑定到插件组件生成的元素
- angular - 角度路由在 CDN 上不起作用
- python - AttributeError:“numpy.ndarray”对象没有属性“convert”和 IndexError 错误:列表索引超出范围