プレイするゲームがないなら、自分で作ればいいじゃない!
ということで Unity 初心者が「ゲームを作る」ゲームをやっていきます!
今回は「オプションデータのセーブとロードの対応」の記事です
内容
Json形式でオプションデータの「セーブとロード」を実装する
Jsonとは
Json とはデータ形式のひとつ
Unity で少しサポートされているので使ってみることに
セーブデータのスクリプト
オプションのデータを作成
[System.Serializable]
public class OptionData
{
public float BgmVolume = 1;
public float SeVolume = 1;
}
データを Json 形式にする
OptionData optionData = new OptionData();
string jsonData = JsonUtility.ToJson(optionData);
Debug.Log(jsonData);
JsonUtility.ToJson(object)
データのクラスや構造体を Json データに変更してくれる
Json データをデータに反映する
JsonUtility.FromJsonOverwrite(jsonData, optionData);
JsonUtility.FromJsonOverwrite(string, object)
Json データから読み取ることでオブジェクトのデータを上書きする
Json データの読み書き
セーブするデータは用意できたので
次は「セーブ&ロードの処理」を追加します
Jsonデータの読み書き用スクリプト
using System.IO;
using System.Threading.Tasks;
public class JsonSaveData<Tdata>
{
enum eState
{
NO_PATH = 0, // 初期状態
IDLE, // パス設定後、動いていない
SAVING, // セーブ中
LOADING, // ロード中
}
string jsonData = "";
string path;
eState state = eState.NO_PATH;
// パスの設定:ついでにファイルが存在するかを返す
public bool SetPath(string _path)
{
path = _path;
state = eState.IDLE;
return File.Exists(path);
}
// セーブする
public async Task Save()
{
if (!IsIdle()) { return; }
state = eState.SAVING;
StreamWriter writer = new StreamWriter(path);
await writer.WriteAsync(jsonData);
writer.Close();
state = eState.IDLE;
}
// ロードする
public async Task Load()
{
if (!IsIdle()) { return; }
state = eState.LOADING;
StreamReader reader = new StreamReader(path);
jsonData = await reader.ReadToEndAsync();
reader.Close();
state = eState.IDLE;
}
// アイドル状態か
public bool IsIdle()
{
return (state == eState.IDLE);
}
// jsonDataを更新
public void UpdateData(Tdata _data)
{
jsonData = JsonUtility.ToJson(_data);
}
// データを取得
public void GetData(Tdata _data)
{
JsonUtility.FromJsonOverwrite(jsonData, _data);
}
}
await StreamWriter.WriteAsync(string)
データを非同期で書き込む
書き込みが終わるまで処理が中断され、
完了したら続きの Close を処理して、IDLE 状態にする
await StreamReader.ReadToEndAsync()
データを非同期で読み込む
読み込みが終わるまで処理が中断され、
完了したら続きの Close を処理して、IDLE 状態にする
セーブとロードの実装
フレームレートの設定で使った GameSystem を
オプションデータのセーブ&ロード用に改造します
public class GameSystem : MonoBehaviour
{
enum eStep
{
INIT = 0,
IDLE,
SAVING,
}
public static GameSystem Instance { get; private set; } = null; // シングルトン
OptionData optionData = new OptionData();
JsonSaveData<OptionData> optionSaveData = new JsonSaveData<OptionData>();
eStep step = eStep.INIT;
void Awake()
{
if (Instance == null)
{
// インスタンスがない場合は代入
Instance = this;
// シーン切り替え時に消さないようにする
DontDestroyOnLoad(this.gameObject);
}
else
{
// ある場合は2つ目なのでゲームオブジェクトを消す
Destroy(this.gameObject);
return;
}
// オプションデータの初期化
if( optionSaveData.SetPath(Application.dataPath + "/option_data.json") )
{
optionSaveData.Load();
}
else
{
Save();
}
}
void Update()
{
switch (step)
{
case eStep.INIT:
{
// データの処理が終わった
if (optionSaveData.IsIdle())
{
optionSaveData.GetData(optionData);
SoundManager.Instance.SetBgmVolume(optionData.BgmVolume);
SoundManager.Instance.SetSeVolume(optionData.SeVolume);
step = eStep.IDLE;
}
}
break;
case eStep.IDLE:
{
}
break;
case eStep.SAVING:
{
// データの処理が終わった
if (optionSaveData.IsIdle())
{
step = eStep.IDLE;
}
}
break;
}
}
// アイドル状態か
public bool IsIdle()
{
return step == eStep.IDLE;
}
// セーブする
public void Save()
{
optionData.BgmVolume = SoundManager.Instance.bgmVolume;
optionData.SeVolume = SoundManager.Instance.seVolume;
optionSaveData.UpdateData(optionData);
optionSaveData.Save();
step = eStep.SAVING;
}
// オプションデータの取得
public OptionData GetOptionData()
{
return optionData;
}
}
optionSaveData.SetPath(Application.dataPath + “/option_data.json”)
Application.dataPath を指定していますが
これはセーブデータの置きたい場所によって適宜変更が必要です
あとはオプションで値が変更されたときに
GetOptionData で値を変更して、オプションから抜けるときに Save を呼びます
サンプル動画
さいごに
どう実装すれば良い感じになるのか
結構考えましたがこんな感じになりました
全然しっくり来ていないですが
Unity に慣れていけばより良い形を作れるようになるでしょう
コメント