繁体   English   中英

保存游戏状态的最佳方法是什么?

[英]What is the best way to save game state?

我找到了在 Unity3D 游戏引擎中保存游戏数据的最佳方法。
首先,我使用BinaryFormatter序列化对象。

但是听说这种方式有问题,不适合保存。
那么,保存游戏状态的最佳或推荐方法是什么?

就我而言,保存格式必须是字节数组。

但是听说这种方式有问题,不适合保存。

这是正确的。 在某些设备上, BinaryFormatter存在问题。 当您更新或更改课程时,情况会变得更糟。 由于类不再匹配,您的旧设置可能会丢失。 有时,由于此原因,您在读取保存的数据时会出现异常。

此外,在 iOS 上,您必须添加Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes"); 否则您将遇到BinaryFormatter问题。

最好的保存方法是使用PlayerPrefsJson 你可以在这里学习如何做到这一点

就我而言,保存格式必须是字节数组

在这种情况下,您可以将其转换为 json,然后将 json string转换为byte数组。 然后您可以使用File.WriteAllBytesFile.ReadAllBytes来保存和读取字节数组。

这是一个可用于保存数据的 Generic 类。 几乎-同,但它使用PlayerPrefs 它使用文件来保存 json 数据。

DataSaver类:

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;
    }
}

用法

要保存的示例类

[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");

我知道这篇文章很旧,但如果其他用户在搜索保存策略时也发现了它,请记住:

PlayerPrefs用于存储游戏状态。 它被明确命名为“PlayerPrefs”以表明其用途:存储玩家偏好。 它本质上是纯文本。 任何玩家都可以轻松定位、打开和编辑它。 这可能不是所有开发人员都关心的问题,但对于许多具有竞争力的游戏来说却很重要。

将 PlayerPrefs 用于选项菜单设置,如音量滑块和图形设置:您不关心播放器可以随意设置和更改它们的东西。

使用 I/O 和序列化来保存游戏数据,或将其作为 Json 发送到服务器。 这些方法比 PlayerPrefs 更安全,即使您在保存前对数据进行了加密。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM