[英]Unity3D Save or Load each Level and their own variables
我是 stackoverflow 和 Unity3D 的新手,所以如果我做错了,我很抱歉。
所以目前,我正在制作一款益智游戏。 它有50个不同的级别。 我需要为他们每个人保存 3 或 4 个变量。 例如,当级别 1 被清除时,我希望它存储 (int)hitCounts、(bool)cleared、(int)bestHitCounts。 我不想使用 playerPrefs,因为我不希望它可以从盒子外面读取。 我希望将其转换为二进制文件。 这是我所拥有的:
#1:制作了一个 static class TGameDat
[System.Serializable]
public class TGameDat
{
public int tGameDatInt;
public bool tGameDatBool;
public int tSceneIndex;
public TGameDat (TPlayer player)
{
tGameDatInt = player.tInt;
tGameDatBool = player.tBool;
tSceneIndex = player.tScene;
}
}
#2:然后制作 Tplayer(monobehaviour)
public class TPlayer : MonoBehaviour
{
public int tInt = 0;
public bool tBool = false;
public int tScene;
public List<TPlayer> TestGameDatList = new List<TPlayer>();
private void Start()
{
TSceneMaker();
}
public void TSceneMaker()
{
tScene = SceneManager.GetActiveScene().buildIndex;
}
public void TNextScene()
{
SceneManager.LoadScene(tScene + 1);
}
public void TPreviousScene()
{
SceneManager.LoadScene(tScene - 1);
}
public void TSaveVariables()
{
TSave.TSavePlayer(this);
TestGameDatList.Add(this);
Debug.Log("saved");
Debug.Log(tInt + " " + tBool + " " + tScene);
}
public void TLoadVariables()
{
List<TGameDat> data = TSave.TLoadPlayer(this);
Debug.Log("loaded. data count = " + data.Count + " tSceneIndex " + tScene);
tInt = data[0].tGameDatInt;
tBool = data[0].tGameDatBool;
tScene = data[0].tSceneIndex;
}
}
#3:最后我创建了一个保存和加载系统:
public static class TSave
{
public static void TSavePlayer (TPlayer player)
{
BinaryFormatter formatter = new BinaryFormatter();
List<TGameDat> data = new List<TGameDat>();
string path = Application.persistentDataPath + "/Tsave_" + player.tScene + ".fun";
if(File.Exists(path))
{
FileStream stream = File.Open(path, FileMode.Open);
data.Add(new TGameDat(player));
formatter.Serialize(stream, data);
stream.Close();
}
else
{
FileStream stream = File.Create(path);
data.Add(new TGameDat(player));
formatter.Serialize(stream, data);
stream.Close();
}
}
public static List<TGameDat> TLoadPlayer(TPlayer player)
{
string path = Application.persistentDataPath + "/Tsave_" + player.tScene + ".fun";
if(File.Exists(path))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = File.Open(path, FileMode.Open);
List<TGameDat> data = new List<TGameDat>();
data = formatter.Deserialize(stream) as List<TGameDat>;
stream.Close();
return data;
}
else
{
Debug.LogError("Save file not found in " + path);
return null;
}
}
}
所以,这是我的问题:
1:当前情况下,每个场景编译一个二进制文件。 所以最后会堆积一堆二进制文件……好像50个,我有50个场景……是不是太多了?
2:当然我试过用List制作一个单独的保存文件,每个级别都会在里面添加自己的变量数据。 但它不会添加数据,而是简单地替换以前的数据。 那么 List 中总是只有 1 个索引。 因此,当我加载时,变量来自上次播放的关卡,而当我在玩完第一个关卡后尝试玩另一个关卡时,因为列表中只有 1 个索引。 我超出范围错误。
我该如何处理? 对不起,很长的文字!
感谢您的投入!
首先,你真的需要每个关卡都有自己的存档数据吗? 因为如果您只需要存储一个级别和另一个级别之间的数据,我建议您使用某种 PlayerState class 来存储上一级别的数据。 但是如果你真的需要存储每个级别的数据,那么我建议你使用字典而不是简单的列表。
这是我将如何做的一个例子
注意:我还没有测试过这段代码!
SaveGameManager class
public string SavePath => Application.persistentDataPath + "/save.dat";
public static SaveGameManager Instance; // Singleton pattern
private Dictionary<string, TGameDat> gameData;
private void Awake()
{
if (Instance != null)
{
Destroy(this.gameObject);
return;
}
// Singleton initialization
Instance = this;
// Keep the object when changing scenes
DontDestroyOnLoad(this.gameObject);
LoadGameData();
}
public TGameDat GetGameData(string key)
{
if (gameData.TryGetValue(key, out TGameDat data))
{
return data;
}
Debug.Log($"Unable to find saved data with key {key}");
return null;
}
public void SetGameData(string key, TGameDat data)
{
// Sets a value with given key and save it to file
gameData[key] = data;
SaveGameData();
}
public void SaveGameData()
{
Serializer.SaveBinaryFile(gameData, SavePath);
}
public void LoadGameData()
{
var savedData = Serializer.LoadBinaryFile(SavePath);
if (savedData != null)
{
gameData = (Dictionary<string, TGameDat>)savedData;
}
else
{
// Creating and saving new data because we can't found
// any that already stored in path
gameData = new Dictionary<string, TGameDat>();
SaveGameData();
}
}
然后,串行器 class
public static void SaveBinaryFile(object data, string path)
{
using (var stream = new FileStream(path, FileMode.Create))
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, data);
}
}
public static object LoadBinaryFile(string path)
{
if (!File.Exists(path))
{
// Trying to load a file that does not exist
return null;
}
using (var stream = new FileStream(path, FileMode.Open))
{
var formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}
}
然后你可以像这样使用它
public TGameDat data;
public void TSaveVariables()
{
SaveGameManager.Instance.SetGameData(level.id, this.data);
}
public void TLoadVariables()
{
var savedData = SaveGameManager.Instance.GetGameData(level.id);
if (savedData != null)
{
this.data = savedData;
}
else
{
// We don't have any save file for this level yet
savedData = new TGameDat();
}
}
您可以将level.id
更改为您想要使用的任何标识符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.