UnityのPlayerPrefsが使いづらい…
Unityで使えるPlayerPrefsを使っている方は多いと思います、自分も初めて使った時は感動して多様しました(笑)
ですがPlayerPrefsを使っていくうちに「アレ?なんか使いづらくね?」と気づくわけです。
PlayerPrefs何が使いづらい?
- まず大量のセーブに向いていない点です。例えば100個の値を保存したい場合100回PlayerPrefsを呼び出す必要性があるわけです。
- int型、float型、string型しか保存できない。
- どこに保存してあるかよくわからない。
などなど割と使いづらい点があるわけです。
使いづらいなら作るしかない
使いづらいなら作ればいいじゃない理論でどうせなので作っていきましょう。
欲しい機能
- 1回のSaveで多数の値を保存できる
- セーブする時にフォルダ名、ファイル名を指定できる
- 様々な値を一括で保存できる
これらの機能を最低限つけて作ります。
コード
SaveLoadManager.cs
usingSystem.IO;usingSystem.Runtime.Serialization.Formatters.Binary;usingUnityEngine;publicstaticclassSaveLoadManager{//ベースとなるフォルダ名privateconststringBASE_FOLDER_NAME="/BaseSaveFolder/";//デフォルトのフォルダ名privateconststringDEFAULT_FOLDER_NAME="SaveFolder";/// <summary>/// フォルダー名の基づいてファイルをセーブ及びロードする時に使用するパスを決める/// </summary>/// <param name="folderName">フォルダ名</param>/// <returns>パス</returns>staticstringCreateSavePath(string_folderName=DEFAULT_FOLDER_NAME){stringsavePath;//使っているプラットフォームを確認(IPhoneかどうか確認)if(Application.platform==RuntimePlatform.IPhonePlayer){savePath=Application.persistentDataPath+BASE_FOLDER_NAME;}//それ以外のプラットフォームの場合else{savePath=Application.persistentDataPath+BASE_FOLDER_NAME;}#if UNITY_EDITOR
savePath=Application.dataPath+BASE_FOLDER_NAME;#endif
// セーブパス + SaveManager/savePath=savePath+_folderName+"/";returnsavePath;}/// <summary>/// 保存するファイル名を決める/// </summary>/// <param name="_fileName">ファイル名</param>/// <returns>保存されるファイル名</returns>staticstringSaveFileName(string_fileName){return_fileName+".binary";}/// <summary>/// セーブする/// </summary>/// <param name="_saveObject"></param>/// <param name="_fileName">ファイルの名前</param>/// <param name="_folderName">フォルダの名前</param>publicstaticvoidSave(object_saveObject,string_fileName,string_folderName=DEFAULT_FOLDER_NAME){//セーブパスを決めるstringsavePath=CreateSavePath(_folderName);//ファイル名を決めるstringsaveFileName=SaveFileName(_fileName);//ディレクトリがあるか確認、なければ作成if(!Directory.Exists(savePath)){Directory.CreateDirectory(savePath);}//クラスをバイナリとして扱うBinaryFormatterformatter=newBinaryFormatter();//ファイル作成FileStreamsaveFile=File.Create(savePath+saveFileName);//オブジェクトをシリアル化しディスク上にファイル書き込みformatter.Serialize(saveFile,_saveObject);//書き込み終了saveFile.Close();}/// <summary>/// ロードする/// </summary>/// <param name="_fileName">ファイルの名前</param>/// <param name="_folderName">フォルダの名前</param>/// <returns></returns>publicstaticobjectLoad(string_fileName,string_folderName=DEFAULT_FOLDER_NAME){//セーブパス(指定フォルダ名)を取得stringsavePath=CreateSavePath(_folderName);//バイナリファイル名を取得stringsaveFileName=savePath+SaveFileName(_fileName);//返すデータobjectreturnObject;//Saveディレクトリまたはバイナリファイルが存在しない場合if(!Directory.Exists(savePath)){Debug.LogError("ディレクトリが見つかりませんでした");returnnull;}if(!File.Exists(saveFileName)){Debug.LogError("ファイルが見つかりませんでした");returnnull;}BinaryFormatterformatter=newBinaryFormatter();//ファイル開くFileStreamsaveFile=File.Open(saveFileName,FileMode.Open,FileAccess.Read,FileShare.Read);//バイナリファイルをデシリアル化しオブジェクトに変換するreturnObject=formatter.Deserialize(saveFile);saveFile.Close();returnreturnObject;}}
これでSaveとLoadをどこでもできるようになりました。
使ってみよう
test.cs
usingSystem.Collections;usingSystem.Collections.Generic;usingSystem;usingUnityEngine;publicclasstest:MonoBehaviour{//外部からいじれるように//セーブしたい内容をクラスで用意[Serializable]publicclassStatus{publicstringname;publicfloathp;publicfloatexp;publicintlevel;}[SerializeField]Statusstatus=newStatus(); [SerializeField]Statuskakunin=newStatus();privatevoidUpdate(){//セーブif(Input.GetKeyDown(KeyCode.S)){SaveLoadManager.Save(status,"PlayerStatus","PlayerData");}//ロードif(Input.GetKeyDown(KeyCode.L)){status=(Status)SaveLoadManager.Load("PlayerStatus","PlayerData");}}}
これは使えるかテストするために用意した簡易的な物なのでもし実用的に使うつもりなのであればManagerクラスを作成してそこで管理させてあげるといいと思います。
実行結果
まとめ
まだまだ拡張の余地があると思うので今後もアップグレードしようと思います。