Unityでのデータ保存方法について。
こことかここ
とかを見ながら自分なりに残しておく。
バージョンは2020.3.12f1
保存場所
Pathは
- Application.persistentDataPath
- Application.temporaryCachePath
のどちらかを通常は選択する。
Application.persistentDataPathは一般的なファイル保存のための場所。ゲームのセーブ等はこちら。
Application.temporaryCachePathは消される可能性があるため、キャッシュとして利用する。ランキングデータの一時保存等か。。
上の方はUnityEngine.iOS.Device.SetNoBackupFlag()でiOSのクラウド同期の有無を設定可能。
AndroidはSDカードへの保存をどうするかを指定出来て、PlayerSettingsのOther SettingsからWrite Permissionの設定で。
PlayerPrefsというUnityの標準機能はアプリの設定情報程度なら使えそう。
実際の保存方法
基本的にはシリアライズしたデータをバイナリで保存するのが一番汎用性が高そう。
JSONでも良いが、JSONの場合は暗号化とかしないと改変が非常に簡単。
(軽く調べるとAesEncryptとかでそれほど手間をかけずに暗号化は出来そう)
バイナリも解析できるが、どこまで頑張る必要があるか次第。
というわけで以下のクラスを保存するというのを実際にやってみる。
とりあえず座標位置をセーブしてみる。
setter/getterが面倒なのでPublicにしている
セーブ対象クラス
[System.Serializable]
public class SaveData {
public float x;
public float y;
public float z;
}
セーブデータを扱うクラス
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
public class SaveManager {
private string SaveDirPath;
public void DataSave(SaveData sdata, string fpath, string fname) {
// バイナリで保存
BinaryFormatter bf = new BinaryFormatter();
string saveFilePath = System.IO.Path.Combine(fpath, fname);
using (FileStream file = File.Create(saveFilePath)) {
bf.Serialize(file, sdata);
}
}
public SaveData DataLoad(string fpath, string fname) {
string loadFilePath = System.IO.Path.Combine(fpath, fname);
if (!File.Exists(loadFilePath)) {
Debug.Log("No Load Data. " + loadFilePath);
return null;
}
BinaryFormatter bf = new BinaryFormatter();
SaveData sdata;
using (FileStream file = File.Open(loadFilePath, FileMode.Open)) {
sdata = (SaveData)bf.Deserialize(file);
}
return sdata;
}
public SaveData CreateSaveData(Vector3 pos) {
SaveData sdata = new SaveData();
sdata.x = pos.x;
sdata.y = pos.y;
sdata.z = pos.z;
return sdata;
}
}
ファイルの保存場所はこのクラスで
private string SaveDirPath = Application.persistentDataPath
のようには取得出来ない。
UnityException: get_persistentDataPath is not allowed to be called from a MonoBehaviour constructor
のようなエラーが出るのでMonoBehaviourを継承したクラスでAwakeで取得するといいエラーが出なかった。
今回は実際にプレーヤーコントロールを行っているクラスで設定して渡すようにしてやった。
SaveManager saveManager = new SaveManager();
string SaveDirPath;
private void Awake()
{
//略
SaveDirPath = Application.persistentDataPath;
}
private void Update()
{
//略
if (Input.GetKey(KeyCode.P)){
SaveData sdata = saveManager.CreateSaveData(this.transform.position);
saveManager.DataSave(sdata,SaveDirPath,"test.sv");
}
if (Input.GetKey(KeyCode.O)){
SaveData sdata = saveManager.DataLoad(SaveDirPath,"test.sv");
Vector3 pos= new Vector3(sdata.x,sdata.y,sdata.z);
this.transform.position = pos;
}
}
とりあえず、これで自キャラの位置をクイックセーブ、ロードのような形が出来たのでとりあえずはOK。