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]
特性。
后记
由于个人能力有限,文中不免存在疏漏之处,恳求大家斧正,一起交流,共同进步。
标签:aes,管理器,string,filePath,存档,Unity,using,byte From: https://www.cnblogs.com/kkelin/p/18169508