【Unity】2Dシューティングを作る ~セーブとロード~

Unityでセーブとロード unity

プレイするゲームがないなら、自分で作ればいいじゃない!

ということで 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 に慣れていけばより良い形を作れるようになるでしょう

 

かれいど

ゲームをしたり、作ったり
色々な事に挑戦していきたい!

サッカー観戦も趣味で
主にJ1リーグを観ています。

かれいどをフォローする
unity
スポンサーリンク
シェアする
かれいどブログ

コメント