はじめに
前回このような"ゲームデータの保存と読み込み方法"に関する記事を書きました。
今回は実際に実装してみたいと思います。
まずは簡単に実装してみる
まずはPlayerPrefsを使って簡単に実装してみます。
※セーブデータを定義したDataクラスがあると仮定します。
// 保存 var json = JsonUtility.ToJson(data); PlayerPrefs.SetString(key, json); // 読み込み var json = PlayerPrefs.GetString(key); var data = JsonUtility.FromJson<Data>(json); // 削除 PlayerPrefs.DeleteKey(Key); // 全て削除 PlayerPrefs.DeleteAll();
Jsonを操作する時にはJsonUtilityを使っています。
JsonUtilityに関する記事もあるので、見てみてください!
少しだけ拡張してみる
保存するためのキーをコンストラクタで渡すようにしました。
読み込み、保存時処理はジェネリックで実装しました。
using UnityEngine; public class SaveData { private string customKey; protected virtual string Key { get { return "SaveData." + GetType() + customKey; } } public SaveData(string key) { customKey = key; } public T Load<T>() where T : new() { var json = PlayerPrefs.GetString(Key); return JsonUtility.FromJson<T>(json); } public void Save<T>(T data) where T : new() { var json = JsonUtility.ToJson(data); PlayerPrefs.SetString(Key, json); } public void Delete() { PlayerPrefs.DeleteKey(Key); } public static void DeleteAll() { PlayerPrefs.DeleteAll(); } }
具体的な実装
更にデータを暗号化して保存してみます。
cryptorは暗号化の実装を変更できるようにインターフェースにしてみました。
今回実装したAESについてはこちらを参照
Advanced Encryption Standard - Wikipedia
実装方法についてはこちら
RijndaelManaged クラス (System.Security.Cryptography) | Microsoft Docs
public class SaveData<T> where T : SaveData<T>, new() { private string customKey = string.Empty; private ICryptor cryptor; protected virtual string Key { get { return string.Format("{0}.{1}.{2}", GetType(), typeof(T), customKey); } } public SaveData() { cryptor = new AESCryptor(); Load(); } public SaveData(string key) { customKey = key; } public void Load() { var encryptedData = PlayerPrefs.GetString(Key); var json = cryptor.Decrypt(encryptedData); JsonUtility.FromJsonOverwrite(json, this); } public void Save() { var json = JsonUtility.ToJson(this); var encryptedData = cryptor.Encrypt(json); PlayerPrefs.SetString(Key, encryptedData); PlayerPrefs.Save(); } public void Delete() { PlayerPrefs.DeleteKey(Key); } public static void DeleteAll() { PlayerPrefs.DeleteAll(); } } public class AESCryptor : ICryptor { private const string AES_IV = "KPQASpi3HmAYvGAE"; private const string AES_KEY = "NEGsvvr9KB3PvHhF"; public string Encrypt(string data) { return Encrypt(data, AES_KEY, AES_IV); } public string Decrypt(string data) { return Decrypt(data, AES_KEY, AES_IV); } public static string Encrypt(string text, string key, string iv) { using (var rijAlg = new RijndaelManaged()) { rijAlg.Key = Encoding.UTF8.GetBytes(key); rijAlg.IV = Encoding.UTF8.GetBytes(iv); var cryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV); using (var ms = new MemoryStream()) { using (var cs = new CryptoStream(ms, cryptor, CryptoStreamMode.Write)) { using (var sw = new StreamWriter(cs)) { sw.Write(text); } } return Convert.ToBase64String(ms.ToArray()); } } } public static string Decrypt(string text, string key, string iv) { using (var rijAlg = new RijndaelManaged()) { rijAlg.Key = Encoding.UTF8.GetBytes(key); rijAlg.IV = Encoding.UTF8.GetBytes(iv); var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV); using (var ms = new MemoryStream(Convert.FromBase64String(text))) { using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) { using (var sr = new StreamReader(cs)) { return sr.ReadToEnd(); } } } } } } public class GameData : SaveData<GameData> { public static GameData Data { get; } = new GameData(); public string id; }
実際に動かしてみます。
まずは以下を実行してみます。
var data = GameData.Data;
data.id = "user_id";
data.Save();
次にアプリを再起動し、ログを出力してみます。
var data = GameData.Data; data.Load(); Debug.Log("id:" + data.id);
実行してみます…
期待通り、"user_id"という文字列が出力されました!
最後に
今回はコンストラクタでLoadを呼んでいますが、
わかりづらいようであれば、分けてもいいかなと思います。
セーブデータをファイルに保存するパターンの実装も紹介できれば紹介したいと思います。
参考
Unityでセーブデータを暗号化してSerialize保存 ~その2~ - Qiita
【Unity】Jsonファイルとしてデータを保存する - Qiita
いい感じのUnity用セーブデータ管理クラス🎍 - Qiita
RijndaelManaged クラス (System.Security.Cryptography) | Microsoft Docs