gracetory’s blog

東池袋にある合同会社グレストリのエンジニアブログです

Unity2019.3.4でEasy Save 3を使ってみた

f:id:grshizawa:20200317131033p:plain

はじめに

最近、Unityでのゲームアプリ開発でいろんなアセットを触る機会がありました。
その中で今回は有料アセットの「Easy Save」を使って
簡単なセーブ機能を作ったのでブログにします。

環境

・MacOS
・Unity(2019.3.4f1)
・Easy Save - The Complete Save & Load Tool for Unity(v3.1.4)

Easy Save とは

読んで字の如く、簡単にセーブできるアセット。
機能としては、データの暗号化から、セーブとロードが簡単に行えます。
保存には多くの型に対応していて、 オーディオファイル、プレハブも保存できるみたいです。
その他、オートセーブ機能やクラウドサーバーにデータのUp/Downloadできる機能などがあります。多機能。

ドキュメントはこちら
docs.moodkie.com

やりたいこと

クラスを丸ごと保存、読み込みをしたい。
例えば下記のようなクラスを暗号化して、保存、読み込みをする。

   // データ項目
    public class Items {
        public string _appversion;    // アプリVer
        public long _beginUnixTime;   // ゲーム開始日
        public int _gold;         // 所持ゴールド
    }

やってみる

アセット導入

下記から購入して、Unityプロジェクトへインポート。 assetstore.unity.com

ヒエラルキーを確認すると
「Easy Save 3 Manager」というオブジェクトが勝手に生成されてます。 f:id:grshizawa:20200317142059p:plain
Unity Editorでシーンを切り替えると毎回勝手に生成されるのが嫌なので、無効にします。

Easy Save設定の変更

Easy SaveのWindowを開きます。 f:id:grshizawa:20200317154454p:plain

Settingタブの「Auto Add Manager to Scene」のチェックを外します。
これで勝手に生成されないようになりました。
他の設定については、スクリプトから行うので触っていません。 f:id:grshizawa:20200317142225p:plain

ついでにAuto Save機能はいらないので、AutoSaveタブで
「Save Event」「Load Event」をNoneに設定します。
f:id:grshizawa:20200317145232p:plain

これで「Easy Save 3 Manager」が勝手に生成されないようになったので、
複数シーンを行き来する場合は自分でインスタンス化する必要があります。

Easy Save 3 Managerの生成

勝手に作成されていた「Easy Save 3 Manager」をプレハブ化。 f:id:grshizawa:20200317150153p:plain

シーン実行時にプレハブをインスタンス化します。
Test.cs

   void Start() {
        // Easy Save 3 Managerを生成
        var prefab = Resources.Load("Prefab/Easy Save 3 Manager") as GameObject;
        var easySaveManagerObj = Instantiate(prefab);
        easySaveManagerObj.name = "Easy Save 3 Manager";
    }

次にEasy Saveの機能を管理するスクリプトを作成していきます。

Easy Save管理スクリプト作成

SaveUtil.cs

/**
 * セーブロード処理
 */
public class SaveUtils {
    // 暗号化パス
    private const string ENCRYPTION_PASS_KEY = "abcdefghi";

    // ファイル名
    private const string FILE_NAME = "SaveData.es3";

    // 設定ファイル
    public static ES3Settings _es3Setting;

    // 初期化
    public static void Init() {
        // セーブファイルの暗号化、データ形式の設定
        _es3Setting = new ES3Settings() {
            encryptionType = ES3.EncryptionType.AES,        // 暗号化の種類
            encryptionPassword = ENCRYPTION_PASS_KEY,       // 暗号化Password
            location = ES3.Location.File,                   // 保存形式
            directory = ES3.Directory.PersistentDataPath,   // 保存場所
            path = FILE_NAME,                               // ファイル名(パス)
        };
    }

    // データを保存する
    public static void Save<T>(string key, T data) {
        // 保存
        ES3.Save<T>(key, data, _es3Setting);
    }

    // データをロードする。
    public static T Load<T>(string key) {
        // keyのデータが存在するか
        if (!ES3.KeyExists(key, _es3Setting)) {
            return default;
        }
        // ロード
        return ES3.Load<T>(key, _es3Setting);
    }

    // データを削除する
    public static void Delete(string key) {
        // キーに該当するファイルが存在しない場合でも例外はスローされない
        ES3.DeleteKey(key, _es3Setting);
    }
}

原則、このクラスにアクセスして、セーブ、ロードを行うようにします。
クラスを丸ごと引数に渡せば良しなにセーブしてくれています。
設定はUnity Editor Windowからも行えますが、
スクリプトから設定を行うようにしています。(Init関数)

保存、読み込み、削除処理

呼び出し元のスクリプトに処理を追加します。
Test.cs

/**
 * testシーン管理
 */
public class Test : MonoBehaviour {
    // データ項目
    public class Items {
        public string _appversion;    // アプリVer
        public long _beginUnixTime;   // ゲーム開始日
        public int _gold;         // 所持ゴールド
    }

    Items _items;

    // シーン初期化
    void Start() {
        // Easy Save 3 Managerを生成
        var prefab = Resources.Load("Prefab/Easy Save 3 Manager") as GameObject;
        var easySaveManagerObj = Instantiate(prefab);
        easySaveManagerObj.name = "Easy Save 3 Manager";

        ///////////// 以下追加 /////////////
        
        // 初期化
        SaveUtils.Init();

        /*********** Save *********/
        // 保存内容作成
        _items = new Items {
            _appversion = "1.0.0",
            _beginUnixTime = 1584425886,
            _gold = 100
        };

        // 保存
        SaveUtils.Save("Items", _items);
        /**************************/

        /*********** Load *********/
        //// ロード、Json化してデバッグログで確認
        //_items = SaveUtils.Load<Items>("Items");
        //var json = JsonUtility.ToJson(_items);
        //Debug.Log(json);
        /**************************/

        /*********** Delete *********/
        //// キーを指定して削除
        //SaveUtils.Delete("Items");
        /****************************/
    }
}

手を抜いて、コメント「Save」「Load」「Delete」箇所のコメントアウトを付け替えて試しています。
セーブするkeyと実体を引数に渡すだけでOK。

Saveの確認
Unity Editor実行後、Easy Saveの設定画面のToolsタブにて
「Open Persistent Data Path」をクリックすると保存先が確認できます。
(ちなみに「Clear Persistent Data Path」はディレクトリ内全てのファイルが削除されますご注意ください)
f:id:grshizawa:20200317160832p:plain
ファイルが作成されていることが確認できました。

SaveData.es3の中身

v��ܾ8f����r;�{Z#ѩ�r�ꨐC2u�h$I�祐�j#���lZ$��vD�bP���w��%@����M!�4п�}�IlU~(��Q�k�Jि39Pu�zo��/9�ߑ�B�TGk��:����^�".�(����8��5

中身は暗号化されていて、何が保存されているかパッと確認できないので
開発中は暗号化設定はしなくてもいいかもしれません。

Loadの確認
f:id:grshizawa:20200317172156p:plain
Loadの部分だけ実行されるようにして確認。
デバッグログにJson表示が表示されています。

Deleteの確認
保存先のファイルの中身が空になっていることを確認(ファイル削除はされません)。

以上でセーブ、ロード、データ削除を実装できました。しかし、

実機でエラー

iOS端末で実行してみるとエラーが出ました。(Androidも)

Default settings were not found in scene. Please drag the ES3 default Setting prefab found in Plugins/Easy Save 3/Resources/ES3/into this scene.

Plugins / Easy Save 3 / Resources / ES3 /ES3 Default Settings
このプレハブがシーンにないという旨のエラーのようです。

ソリューション全体に「ES3 Default Settings 」で文字検索をかけてみると、
このプレハブを生成しているところを発見。

原因はEasy Saveアセットの下記スクリプト

Assets/Plugins/Easy Save 3/Scripts/Settings/ES3Settings.cs

146行目〜
    internal static void LoadDefaults()
    {
       #if !UNITY_EDITOR
これ→   //var go = Resources.Load<GameObject>("ES3/ES3 Default Settings");
これ→   var go = GameObject.Find("ES3 Default Settings");
        if(go == null)
        {
            Debug.LogError("Default settings were not found in scene. Please drag the ES3 Default Settings prefab found in Plugins/Easy Save 3/Resources/ES3/ into this scene.");
            return;
        }
       #else
        var go = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(UnityEditor.AssetDatabase.GetAssetPath(Resources.Load<GameObject>("ES3/ES3 Default Settings")));
       #endif  
        var component = go.GetComponent<ES3DefaultSettings>();
        if(component == null)
            return;
        _defaults = component.settings;
    }

これは・・・テストコードが残ってた?

> これ→ var go = Resources.Load<GameObject>("ES3/ES3 Default Settings");
> これ→  //var go = GameObject.Find("ES3 Default Settings");  

上記コメントアウトを入れ替えて実行してみたところ、無事正常に動作しました。

最後に

今回、Easy Saveでの実装は最低限の内容になっていますが、
他にも様々な便利機能があるので追々検証してみたいと思います。