データ保存!UnityでSave/Load機能を実装しよう!基礎編

ゲームを作ってると、必ずと言っていいほど状況を保存したり再現したりする必要が出てきます。ここでは基本のデータ保存術をご紹介したいと思います。

目次

データ保存・読込みの基本

複雑なセーブデータの扱いになっても基本的には同じです。

簡単な手順をおさらいと今回やること

データの保存・読込みを行うには次の手順で行います

  • 保存するデータの定義
    • JsonUtilityを使って定義
  • 保存データを作成
    • PlayerPrefsを使う
    • Persistent Data Path
    • PlayFabなんかもあり
  • 保存したデータを読み込む
    • 保存データからのResume

また、今回は基本ということで次のようなデータの保存と読込み反映を行いたいと思います。

  • キャラクターの位置
  • Healthなどキャラクターに準じたパラメータ

下準備

シンプルな2Dのキャラクターを動かすスクリプトを作成します。画像をインポートして、SpriteRendererで表示されたキャラクターに下記スクリプトをアタッチして動く状態にして準備完了!

using UnityEngine;

public class SaveLoadSample : MonoBehaviour
{
    public float speed = 5.0f;

    private void Update()
    {
        // 上下左右で移動
        float x = Input.GetAxis("Horizontal");
        float y = Input.GetAxis("Vertical");
        transform.position += new Vector3(x, y, 0) * speed * Time.deltaTime;
    }
}

データを保存する

まずは基本となる保存データを準備します。

データの準備

今回はキャラクターの位置と、HP(health)を保存データに入れたいと思います。保存するためのデータの型を新たに用意してみます。また確認用にHealthを増やしたり減らしたりする処理と、位置と現在のHealthを表示するデバッグ機能も追加してみます。

  • データ保存を行う型、UserDataを宣言
    • 後の処理のためにSystem.Serializableを追加
    • 保存する変数をpublicで追加
  • Healtを操作するデバッグ機能追加
    • 1キーで10Healthが減る
    • 2キーでHealthが10増える
  • 3キーでデバッグ表示
    • 現在のPosition
    • 現在のHealth
using UnityEngine;

[System.Serializable]
public class UserData
{
    public Vector3 position;
    public float health;
}

public class SaveLoadSample : MonoBehaviour
{
    public float speed = 5.0f;
    public float health = 100.0f;

    private void Update()
    {
        // 上下左右で移動
        float x = Input.GetAxis("Horizontal");
        float y = Input.GetAxis("Vertical");
        transform.position += new Vector3(x, y, 0) * speed * Time.deltaTime;

        // ダメージを受ける
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            health -= 10.0f;
        }

        // 回復する
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            health += 10.0f;
        }

        // 位置とHealthの状態をコンソールに表示
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            Debug.Log("Position: " + transform.position);
            Debug.Log("Health: " + health);
        }
    }
}

保存データの文字列化:JsonUtility

データはUserDataクラスの形式で保存を行いますが、実際に保存する場合は文字列に変換して保存を行います。クラスのメンバ変数を文字列に変換するには、そのクラスに[System.Serializable]をつける必要があります。また文字列に変換するためには、JsonUtilityというものを使います。Jsonデータについて詳しく知りたい場合はこちらのリンクをご参照ください

ここでは保存するつもりのKキーを押すことで、現在のPositionやHealthをJsonデータで確認するプログラムを作成します。キャラを動かしたりしてKキーをおしてコンソールビューを確認してみてください。

public class SaveLoadSample : MonoBehaviour
{
    private void Update()
    {
        // -----------------------------
        // 他のコードは省略しています
        // -----------------------------

        // 以下を追加
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            UserData data = new UserData()
            {
                position = transform.position,
                health = health
            };
            string json = JsonUtility.ToJson(data ,true);
            Debug.Log(json);
        }
    }
}

実際にデータを保存する

Jsonデータに出力できるようになったら、いよいよデータの保存を行いましょう。今回はPlayerPrefsを使ってデータを保存したいと思います。後々にEasySaveなどのアセットを使う場合にも同じような手触りで利用することが出来ます。PlayerPrefsでは各プラットフォームごとにデータを保存することが可能です。近い機能としてはDictionaryになります。鍵となるKeyと値のValueが対(つい)となって保存されます。

  • PlayerPrefs.HasKey(string key)
    • キーがすでに使われているかどうかを確認
  • PlayerPrefs.SetString(string key , string value)
    • データを保存する
    • 保存する場合はキーと値が必要
    • 文字列の他にint型とfloat型バージョンもある
  • PlayerPrefs.GetString(string key )
    • Setで保存されたものを取り出す
    • 第2引数に未保存の場合のデフォルトの値を仕込むバージョンもある
    • 文字列の他にint型とfloat型バージョンもある
  • PlayerPrefs.Save()
    • Set系を呼んだあとにこのメソッドで保存されます。
スライム

例外的に形が異なる場合は同じKeyが使えますが、狙って利用しないのが良いでしょう。

では実際にKキーを押したあとにJsonデータを保存してみましょう。保存するキーの名前は「PlayerUserData」としましょう。

public class SaveLoadSample : MonoBehaviour
{
    private void Update()
    {
        // -----------------------------
        // 他のコードは省略しています
        // -----------------------------

        // 以下を追加
        if (Input.GetKeyDown(KeyCode.K))
        {
            UserData data = new UserData()
            {
                position = transform.position,
                health = health
            };
            string json = JsonUtility.ToJson(data, true);
            Debug.Log(json);  // ←この行は消してもOK

            // 追加行はここから
            PlayerPrefs.SetString("PlayerUserData", json);
            PlayerPrefs.Save();
        }
    }
}

データを取り出して反映する

保存出来たら取り出して反映してみましょう。Lキーを押したときにデータがあれば反映される処理を追加します。一番わかり易いのは位置だと思いますが、Healthが保存状態になっているかを3キー押して確認してみてください。

public class SaveLoadSample : MonoBehaviour
{
    private void Update()
    {
        // -----------------------------
        // 他のコードは省略しています
        // -----------------------------

        if (Input.GetKeyDown(KeyCode.K))
        {
            UserData data = new UserData()
            {
                position = transform.position,
                health = health
            };
            string json = JsonUtility.ToJson(data, true);
            Debug.Log(json);  // ←この行は消してもOK

            // 追加行はここから
            PlayerPrefs.SetString("PlayerUserData", json);
            PlayerPrefs.Save();
        }

        // データをロードする処理
        if (Input.GetKeyDown(KeyCode.L))
        {
            if (PlayerPrefs.HasKey("PlayerUserData"))
            {
                string json = PlayerPrefs.GetString("PlayerUserData");
                UserData data = JsonUtility.FromJson<UserData>(json);
                transform.position = data.position;
                health = data.health;
            }
            else
            {
                Debug.Log("PlayerUserDataが存在しません");
            }
        }
    }
}

フルコート

今回利用したソースコード全体図

using UnityEngine;

[System.Serializable]
public class UserData
{
    public Vector3 position;
    public float health;
}

public class SaveLoadSample : MonoBehaviour
{
    public float speed = 5.0f;
    public float health = 100.0f;

    private void Update()
    {
        // 上下左右で移動
        float x = Input.GetAxis("Horizontal");
        float y = Input.GetAxis("Vertical");
        transform.position += new Vector3(x, y, 0) * speed * Time.deltaTime;

        // ダメージを受ける
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            health -= 10.0f;
        }

        // 回復する
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            health += 10.0f;
        }

        // 位置とHealthの状態をコンソールに表示
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            Debug.Log("Position: " + transform.position);
            Debug.Log("Health: " + health);
        }

        if (Input.GetKeyDown(KeyCode.K))
        {
            UserData data = new UserData()
            {
                position = transform.position,
                health = health
            };
            string json = JsonUtility.ToJson(data, true);
            Debug.Log(json);

            PlayerPrefs.SetString("PlayerUserData", json);
            PlayerPrefs.Save();
        }

        if (Input.GetKeyDown(KeyCode.L))
        {
            if (PlayerPrefs.HasKey("PlayerUserData"))
            {
                string json = PlayerPrefs.GetString("PlayerUserData");
                UserData data = JsonUtility.FromJson<UserData>(json);
                transform.position = data.position;
                health = data.health;
            }
            else
            {
                Debug.Log("PlayerUserDataが存在しません");
            }
        }
    }
}
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次