Unity游戏框架设计之存档管理器

Unity游戏框架设计之存档管理器

存档管理器的主要功能是实现游戏进度的查询、存储(存档)、读取(读档)和删除(删档)。

存档主要有三种实现方案。

(一)PlayerPrefs。PlayerPrefs 类用于在游戏中存储、删除、修改和访问玩家的数据。存储的数据是持久化的,即使玩家关闭游戏或重新启动设备,数据也会保留下来。缺陷:PlayerPrefs 是明文存储的。

(二)本地存储:JSON + 加密算法。对于存档操作,先将玩家需要保存的数据封装为实体类,然后通过 JSON 工具将实体类序列化为 JSON 字符串,然后通过加密算法对 JSON 字符串进行加密,保证存档的安全,最后以二进制的方式输出到本地文件中。对于读档操作,则先读取本地二进制文件,然后通过加密算法解密出 JSON 字符串,然后通过 JSON 工具将 JSON 字符串反序列化为实体类即可。

(三)数据库存储。玩家数据将被存储到远程数据库中。玩家在游戏中不断与服务器交互,由服务器来完成游戏业务逻辑的处理,并在数据库中读取和修改玩家数据。

下述代码实现方案二下的存档管理器。

代码设计

public class GameProgressManager : SingletonMono<GameProgressManager>
{
    [Serializable]
    public abstract class GameProgressData
    {
    }

    private static readonly (byte[], byte[]) AesKeyAndIv = new(
        Convert.FromBase64String(""), Convert.FromBase64String("")
    );

    public void CreateGameProgress<T>(T data, string filePath) where T : GameProgressData
    {
        string gameProcessDataJson = JsonUtility.ToJson(data);
        byte[] encryptedData = EncryptStringByAes(gameProcessDataJson, AesKeyAndIv.Item1, AesKeyAndIv.Item2);
        File.WriteAllBytes(filePath, encryptedData);
    }

    public void RemoveGameProgress(string filePath)
    {
        if (File.Exists(filePath))
        {
            File.Delete(filePath);
        }
    }

    public void SaveGameProgress<T>(T data, string filePath) where T : GameProgressData
    {
        string gameProcessDataJson = JsonUtility.ToJson(data);
        byte[] encryptedData = EncryptStringByAes(gameProcessDataJson, AesKeyAndIv.Item1, AesKeyAndIv.Item2);
        File.WriteAllBytes(filePath, encryptedData);
    }

    public bool ContainGameProgress(string filePath)
    {
        return File.Exists(filePath);
    }

    public T GetGameProgress<T>(string filePath) where T : GameProgressData
    {
        byte[] encryptedData = File.ReadAllBytes(filePath);
        string gameProcessDataJson = DecryptStringByAes(encryptedData, AesKeyAndIv.Item1, AesKeyAndIv.Item2);
        return JsonUtility.FromJson<T>(gameProcessDataJson);
    }

    private static byte[] EncryptStringByAes(string plainText, byte[] key, byte[] iv)
    {
        using Aes aes = Aes.Create();
        aes.Key = key;
        aes.IV = iv;
        ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
        using MemoryStream memoryStream = new MemoryStream();
        using CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
        byte[] plaintextBytes = Encoding.UTF8.GetBytes(plainText);
        cryptoStream.Write(plaintextBytes, 0, plaintextBytes.Length);
        cryptoStream.FlushFinalBlock();
        return memoryStream.ToArray();
    }

    private static string DecryptStringByAes(byte[] cipherText, byte[] key, byte[] iv)
    {
        using Aes aes = Aes.Create();
        aes.Key = key;
        aes.IV = iv;
        ICryptoTransform cryptoTransform = aes.CreateDecryptor(aes.Key, aes.IV);
        using MemoryStream memoryStream = new MemoryStream(cipherText);
        using CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Read);
        using StreamReader streamReader = new StreamReader(cryptoStream);
        return streamReader.ReadToEnd();
    }

    private static (byte[], byte[]) GenerateAesKeyAndIv()
    {
        using Aes aes = Aes.Create();
        aes.GenerateKey();
        aes.GenerateIV();
        Debug.Log("AES 密钥 " + Convert.ToBase64String(aes.Key));
        Debug.Log("AES 向量 " + Convert.ToBase64String(aes.IV));
        return (aes.Key, aes.IV);
    }
}

代码说明

(一)使用前需要先生成 AES 密钥和 AES 向量。

(二)所有游戏存档实体类必须继承 GameProgressData 类。

(三)游戏存档实体类中的内部类必须使用 [Serializable] 特性。

后记

由于个人能力有限,文中不免存在疏漏之处,恳求大家斧正,一起交流,共同进步。

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值