保存游戏状态的最佳方法是什么?
What is the best way to save game state?
我找到了在 Unity3D 游戏引擎中保存游戏数据的最佳方式。
首先,我使用 BinaryFormatter
.
序列化对象
但是听说这种方式存在一些问题,不适合保存。
那么,保存游戏状态的最佳或推荐方法是什么?
在我的例子中,保存格式必须是字节数组。
But I heard this way has some issues and not suitable for save.
没错。在某些设备上,BinaryFormatter
存在问题。当您更新或更改 class 时,情况会变得更糟。由于 classes 不再匹配,您的旧设置可能会丢失。有时,因此读取保存的数据时会出现异常。
此外,在 iOS 上,您必须添加 Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
,否则 BinaryFormatter
会出现问题。
最好的保存方式是使用 PlayerPrefs
和 Json
。你可以学习如何做到这一点 .
In my case, save format must be byte array
在这种情况下,您可以将其转换为 json,然后将 json string
转换为 byte
数组。然后,您可以使用 File.WriteAllBytes
和 File.ReadAllBytes
来保存和读取字节数组。
这是一个通用的class,可以用来保存数据。与 几乎相同,但它 而不是 使用 PlayerPrefs
。它使用文件来保存 json 数据。
DataSaver
class:
public class DataSaver
{
//Save Data
public static void saveData<T>(T dataToSave, string dataFileName)
{
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Convert To Json then to bytes
string jsonData = JsonUtility.ToJson(dataToSave, true);
byte[] jsonByte = Encoding.ASCII.GetBytes(jsonData);
//Create Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
}
//Debug.Log(path);
try
{
File.WriteAllBytes(tempPath, jsonByte);
Debug.Log("Saved Data to: " + tempPath.Replace("/", "\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To PlayerInfo Data to: " + tempPath.Replace("/", "\"));
Debug.LogWarning("Error: " + e.Message);
}
}
//Load Data
public static T loadData<T>(string dataFileName)
{
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Exit if Directory or File does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Debug.LogWarning("Directory does not exist");
return default(T);
}
if (!File.Exists(tempPath))
{
Debug.Log("File does not exist");
return default(T);
}
//Load saved Json
byte[] jsonByte = null;
try
{
jsonByte = File.ReadAllBytes(tempPath);
Debug.Log("Loaded Data from: " + tempPath.Replace("/", "\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To Load Data from: " + tempPath.Replace("/", "\"));
Debug.LogWarning("Error: " + e.Message);
}
//Convert to json string
string jsonData = Encoding.ASCII.GetString(jsonByte);
//Convert to Object
object resultValue = JsonUtility.FromJson<T>(jsonData);
return (T)Convert.ChangeType(resultValue, typeof(T));
}
public static bool deleteData(string dataFileName)
{
bool success = false;
//Load Data
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Exit if Directory or File does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Debug.LogWarning("Directory does not exist");
return false;
}
if (!File.Exists(tempPath))
{
Debug.Log("File does not exist");
return false;
}
try
{
File.Delete(tempPath);
Debug.Log("Data deleted from: " + tempPath.Replace("/", "\"));
success = true;
}
catch (Exception e)
{
Debug.LogWarning("Failed To Delete Data: " + e.Message);
}
return success;
}
}
用法:
要保存的示例 class:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
保存数据:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
//Save data from PlayerInfo to a file named players
DataSaver.saveData(saveData, "players");
加载数据:
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
if (loadedData == null)
{
return;
}
//Display loaded Data
Debug.Log("Life: " + loadedData.life);
Debug.Log("High Score: " + loadedData.highScore);
for (int i = 0; i < loadedData.ID.Count; i++)
{
Debug.Log("ID: " + loadedData.ID[i]);
}
for (int i = 0; i < loadedData.Amounts.Count; i++)
{
Debug.Log("Amounts: " + loadedData.Amounts[i]);
}
删除数据:
DataSaver.deleteData("players");
我知道这个 post 很旧,但如果其他用户在搜索保存策略时也找到它,请记住:
PlayerPrefs 不是用于存储游戏状态。它明确 命名为“PlayerPrefs”以表明其用途:存储玩家偏好。它本质上是纯文本。任何玩家都可以轻松找到、打开和编辑它。这可能不是所有开发者都关心的问题,但对许多开发具有竞争力的游戏的人来说很重要。
将 PlayerPrefs 用于选项菜单设置,例如音量滑块和图形设置:您不在乎播放器可以随意设置和更改的内容。
使用I/O和序列化来保存游戏数据,或者将其作为Json发送到服务器。这些方法比 PlayerPrefs 更安全,即使您在保存前加密数据也是如此。
我找到了在 Unity3D 游戏引擎中保存游戏数据的最佳方式。
首先,我使用 BinaryFormatter
.
但是听说这种方式存在一些问题,不适合保存。
那么,保存游戏状态的最佳或推荐方法是什么?
在我的例子中,保存格式必须是字节数组。
But I heard this way has some issues and not suitable for save.
没错。在某些设备上,BinaryFormatter
存在问题。当您更新或更改 class 时,情况会变得更糟。由于 classes 不再匹配,您的旧设置可能会丢失。有时,因此读取保存的数据时会出现异常。
此外,在 iOS 上,您必须添加 Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
,否则 BinaryFormatter
会出现问题。
最好的保存方式是使用 PlayerPrefs
和 Json
。你可以学习如何做到这一点
In my case, save format must be byte array
在这种情况下,您可以将其转换为 json,然后将 json string
转换为 byte
数组。然后,您可以使用 File.WriteAllBytes
和 File.ReadAllBytes
来保存和读取字节数组。
这是一个通用的class,可以用来保存数据。与 PlayerPrefs
。它使用文件来保存 json 数据。
DataSaver
class:
public class DataSaver
{
//Save Data
public static void saveData<T>(T dataToSave, string dataFileName)
{
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Convert To Json then to bytes
string jsonData = JsonUtility.ToJson(dataToSave, true);
byte[] jsonByte = Encoding.ASCII.GetBytes(jsonData);
//Create Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
}
//Debug.Log(path);
try
{
File.WriteAllBytes(tempPath, jsonByte);
Debug.Log("Saved Data to: " + tempPath.Replace("/", "\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To PlayerInfo Data to: " + tempPath.Replace("/", "\"));
Debug.LogWarning("Error: " + e.Message);
}
}
//Load Data
public static T loadData<T>(string dataFileName)
{
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Exit if Directory or File does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Debug.LogWarning("Directory does not exist");
return default(T);
}
if (!File.Exists(tempPath))
{
Debug.Log("File does not exist");
return default(T);
}
//Load saved Json
byte[] jsonByte = null;
try
{
jsonByte = File.ReadAllBytes(tempPath);
Debug.Log("Loaded Data from: " + tempPath.Replace("/", "\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To Load Data from: " + tempPath.Replace("/", "\"));
Debug.LogWarning("Error: " + e.Message);
}
//Convert to json string
string jsonData = Encoding.ASCII.GetString(jsonByte);
//Convert to Object
object resultValue = JsonUtility.FromJson<T>(jsonData);
return (T)Convert.ChangeType(resultValue, typeof(T));
}
public static bool deleteData(string dataFileName)
{
bool success = false;
//Load Data
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Exit if Directory or File does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Debug.LogWarning("Directory does not exist");
return false;
}
if (!File.Exists(tempPath))
{
Debug.Log("File does not exist");
return false;
}
try
{
File.Delete(tempPath);
Debug.Log("Data deleted from: " + tempPath.Replace("/", "\"));
success = true;
}
catch (Exception e)
{
Debug.LogWarning("Failed To Delete Data: " + e.Message);
}
return success;
}
}
用法:
要保存的示例 class:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
保存数据:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
//Save data from PlayerInfo to a file named players
DataSaver.saveData(saveData, "players");
加载数据:
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
if (loadedData == null)
{
return;
}
//Display loaded Data
Debug.Log("Life: " + loadedData.life);
Debug.Log("High Score: " + loadedData.highScore);
for (int i = 0; i < loadedData.ID.Count; i++)
{
Debug.Log("ID: " + loadedData.ID[i]);
}
for (int i = 0; i < loadedData.Amounts.Count; i++)
{
Debug.Log("Amounts: " + loadedData.Amounts[i]);
}
删除数据:
DataSaver.deleteData("players");
我知道这个 post 很旧,但如果其他用户在搜索保存策略时也找到它,请记住:
PlayerPrefs 不是用于存储游戏状态。它明确 命名为“PlayerPrefs”以表明其用途:存储玩家偏好。它本质上是纯文本。任何玩家都可以轻松找到、打开和编辑它。这可能不是所有开发者都关心的问题,但对许多开发具有竞争力的游戏的人来说很重要。
将 PlayerPrefs 用于选项菜单设置,例如音量滑块和图形设置:您不在乎播放器可以随意设置和更改的内容。
使用I/O和序列化来保存游戏数据,或者将其作为Json发送到服务器。这些方法比 PlayerPrefs 更安全,即使您在保存前加密数据也是如此。