2016/06/21
Unityでの永続的なセーブ方法
2016/4/25追記
PlayerPrefsを拡張したような新しいセーブ機能も記事を書いたので、そちらもご参考ください。個人的には下記の方が使いやすいと思います。
PlayerPrefsと同じような使い方で独自クラスもセーブできる機能実装【Unity】【セーブ】【Json】
セーブ機能の概要は本記事をご確認ください。
概要
Unityで開発していると、永続的にゲームデータをセーブしたい場面があるかと思います。
例えば、音量、プレイヤーのレベル、お金、装備品のデータ等々です。
Unityで永続的にデータを保存する方法としては、いくつか実装方法があります。
- Unity標準のPlayerPrefsを使用する。
- 有料Assetを使用する。
- 外部ファイルに読み書き。ローカルに保存。
今回は3の方法で実装しました。まずはそれぞれのセーブ方法の概要を解説していきます。
1. Unity標準のPlayerPrefsを使用する。
単純なデータ、少量のデータにはUnity標準のPlayerPrefsで事足ります。
例えばBGMの音量、SEの音量等はPlayerPrefsで十分ではないでしょうか。
PlayerPrefsの使い方については下記サイトにわかりやすくまとめられていました。
・【Unity開発】Player Prefs(セーブ機能)まとめ【ひよこエッセンス】
PlayerPrefsのデメリットとしては、保存できる型がint, float, string型等のみで、自作classやList型は保存できないことにあります。
2. 有料Assetを使用する。
もう少しリッチな機能を持った有料のAssetもあります。ただし、個人開発であまりお金をかけたくないことや、セーブ機能というゲームにおける最重要部分がブラックボックスになるというリスクをはらんでいます。
また、Unityを使用している学生さんなどにはには有料Assetはハードルが高いかと思いますので、今回は不採用としました。
3. 外部ファイルに読み書き。暗号化も実装。
端末のローカル領域に外部ファイルとして保存し、読み書きする方法です。
1.のPlayerPrefsは大容量のデータ保存には向かない
2. の有料Assetは購入したくない(できない)というわがままな思いを解決すべく、外部ファイルに読み書きする方法を実装しました。
外部ファイル形式としては、csv, json, xmlなどがありますが、classをそのままシリアライズ可能なjsonを採用しました。
またローカルに保存すると、データ解析される可能性もあるので、暗号化も実装しました。
外部ファイルへのセーブ実装方法
大まかな機能としては
・セーブしたい時はGameData.Save()でオブジェクトをjsonに変換⇨暗号化⇨外部ファイルに保存。
・セーブしたデータを取り出したい時は、float volumeBGM = GameData.VolumeBGM;の様に使うだけ。
・Singletonで実装、どこからでも簡単にアクセス可能。
参考にしたページは以下。
・【Unity】LitJsonを使用してデータを超カンタンにセーブする
・【Unity】なんちゃらManagerクラスを作ろう(シングルトン)
・Unityでセーブデータを暗号化してSerialize保存
・Unity開発に関する50のTips 〜ベストプラクティス〜(翻訳): No hack, no work
クラスの実装
上記サイト様を参考に引用させていただいたクラス、作成したクラスは以下の通り。
よくわからない方は下記ソースをコピーしてもらって、最後のGameData.csだけ自分が作成しているアプリに合わせて改造いただければ、良いかなと思います。
- LitJson.dll
- JsonMapper.cs //LitJsonでは変換できないfloat型などのシリアライズに対応させるためのクラス
- Cript.cs //暗号化復号化するクラス
- SavableSingleton.cs //instanceをセーブ可能なSingletonクラス
- SingletonMonoBehaviour.cs //SingletonなMonoBehaivourクラス
- GameData.cs //Sceneのオブジェクトにアタッチしておけば、どこからでもアクセスでき、クラス内で定義したフィールドをGameData.Save()だけで永続的に保存できるクラス。保存データは暗号化されている。
LitJson.dllのダウンロード
LitJsonをダウンロードする。
Unityを開きAssets/Plugins以下にLitJson.dllを保存する。超簡単。
JsonMapper.cs
ポイントと使い方
JsonMapper.ToJson(クラスのオブジェクト)でjson化した文字列を返す。
JsonMapper.ToObject<クラス名>(クラスのオブジェクト)でデシリアライズ
Cript.cs
ポイントと使い方
string encriptedStr = Cript.Encrypt(暗号化したい文字列);
で、文字列の暗号化
string decriptedStr = Cript.Decrypt(暗号化した文字列);
で暗号化された文字列の復号化
SavableSingleton.cs
ポイントと使い方
・クラス名.Save()で、
public static string folderPath = Application.persistentDataPath + "/Database/" ; public static string filePath = folderPath+ typeof(T).FullName + ".json";
で指定したフォルダ、ファイル名にjsonファイルを暗号化した形式で保存。
・ロードはinstanceを生成する時点で実施されるので、外部から使用する際は別段気にする必要はない。
SingletonMonoBehaviour.cs
ポイントと使い方
そのままズバリ、singletonなMonoBehaviour。上記naichilab様の記事をご参考ください。
GameData.cs
ポイントと使い方
- GameDataクラスの中にSaveDataクラスを作成。
- GameDataはSingletonなMonoBehaviourで、ゲームを通して、インスタンスが1つしか生成されない。
- SaveDataクラスはSavableSingletonを継承しており、これもSingletonでインスタンスが一つしか生成されない。SaveData.Save()でインスタンスのデータがSavableSingleton.csで指定したフォルダに生成される。
- 外部から使用する時は、本来 GameData.SaveData.Instance.VolumeSEの様にアクセスする必要があるところを、staticなプロパティを記述しておくことで、GameData.VolumeSEとアクセスできる様になり、綺麗に書ける。
使い方
使い方は適当なオブジェクト(名前はGameDataにした)をSceneに配置して、GameData.csをアタッチする。
GameData.csを使用する適当なテストコードを作成。今回は以下のようなものを作成してみた。
GameDataUser.cs
上記スクリプトをScene上のオブジェクトに適当にアタッチ
Consoleでセーブできてるかを確認。一度再生した後、再度再生すると値が保存されていると思う。
これで超簡単?に使えるSave機能の完成。多分Listなんかもセーブできると思う。。。真面目に検証してない。
保存データはSavableSingleton.csで指定したパスに保存されるけど、パスの指定を変えたりすれば、サーバに保存とかもできるんじゃないかと思う。
コードの改善点や、本場のゲーム開発現場で、もっと良い方法あるよって方がいらっしゃいましたら、教えていただけると幸いです。
2016/4/25追記
PlayerPrefsを拡張したような新しいセーブ機能も記事を書いたので、そちらもご参考ください。個人的には下記記事の方が使いやすいかなーと思います。
コメント
Json関連は5.3からUnityの標準機能に入ったのでそちら使ったほうがいいかもですよー
LitJsonは使いやすいんですが、IL2CPPとかでビルドミスることが多いのでできれば使いたくない感じー
by しろくろ 2016年1月11日 6:12 PM
コメントいただき、ありがとうございます!
Json関連は標準機能になったんですね。調べてみます。
by Magnagames 2016年1月11日 6:51 PM