データを保存しよう:PlayerPrefsとJSON【Unityスタートガイド12-6】

ゲームを終了しても、ハイスコアや設定、進み具合は覚えておいてほしいですよね。普通の変数は、ゲームを終了すると消えてしまいます。今回は、Unityでデータを保存する2つの方法、手軽なPlayerPrefsと、まとまったデータを保存できるJSONをご紹介します!

目次

この記事で学べること

  • PlayerPrefsで数値や文字列を保存・読み込みする方法
  • PlayerPrefsが向いているもの・向いていないもの
  • JsonUtilityで、クラスのデータをJSONの文字列にする方法
  • JSONをファイルに保存・読み込みする方法(Application.persistentDataPath)

前提知識

2つの保存方法

方法向いているもの向いていないもの
PlayerPrefsハイスコア、音量、最後に選んだステージなどの少ない値たくさんのデータ、アイテムの一覧、なくなると困るデータ
JSON+ファイルセーブデータ(レベル、所持金、アイテムの一覧など)―(少し書く量が増える)

PlayerPrefs:手軽に値を保存する

保存と読み込み

using UnityEngine;

public class SaveHighScoreExample : MonoBehaviour
{
    private const string HighScoreKey = "HighScore";

    void Start()
    {
        // 読み込み。まだ保存されていなければ、2つ目の値(0)が返る
        int highScore = PlayerPrefs.GetInt(HighScoreKey, 0);
        Debug.Log("前回のハイスコア: " + highScore);
    }

    // スコアが決まったときに呼ぶ
    public void SubmitScore(int score)
    {
        int highScore = PlayerPrefs.GetInt(HighScoreKey, 0);

        if (score > highScore)
        {
            PlayerPrefs.SetInt(HighScoreKey, score);
            PlayerPrefs.Save();
            Debug.Log("ハイスコア更新! " + score);
        }
    }
}
  • 保存:PlayerPrefs.SetInt(キー, 値)、SetFloat、SetString
  • 読み込み:PlayerPrefs.GetInt(キー, 保存されていないときの値)、GetFloat、GetString
  • キー:保存する値の名前。保存と読み込みで同じ文字列を使うので、上のようにconstで1か所にまとめておくと、つづり間違いを防げます
  • PlayerPrefs.Save():すぐに書き込む。ゲームを普通に終了したときも自動で保存されますが、強制終了に備えて大事なタイミングで呼んでおくと安心です

そのほかの便利なメソッド

書き方内容
PlayerPrefs.HasKey(キー)そのキーが保存されているか(true/false)
PlayerPrefs.DeleteKey(キー)そのキーを消す
PlayerPrefs.DeleteAll()全部消す(テストでやり直したいときに)

エディタでテストしたデータを消したいときは、上部メニューのEdit>Clear All PlayerPrefsでも全部消せます。

どこに保存される?

PlayerPrefsは、パソコンやスマホの中の、Unityが決めた場所に保存されます。

  • Windows:レジストリ(ファイルとしては見えない場所)
  • Mac:~/Library/Preferences の中のファイル
  • Web:ブラウザの保存領域

プロジェクトのフォルダには保存されないので、Assetsを見ても出てきません。保存場所はProject SettingsのPlayerにあるCompany NameとProduct Nameで決まるので、あとから変えると前のデータが読めなくなります。

PlayerPrefsに向いていないもの

  • たくさんのデータ:アイテムの一覧など。キーがどんどん増えて管理できなくなります
  • なくなると困るデータ:ユーザーが簡単に中身を書き換えたり消したりできます
  • 複雑なデータ:int・float・stringの3種類しか保存できません

こういうデータは、次のJSONを使いましょう。

スライム

PlayerPrefsに全部入れていたら、キーの名前が何十個にもなって訳が分からなくなった・・・

フェアリー

まとまったデータはクラスにまとめてJSONで保存するとスッキリするよ!次の節を見てみてね

JSON:まとまったデータをファイルに保存する

JSONとは

JSONは、データを文字で表す書き方の1つです。例えばこんな形です。

{"playerName":"勇者","level":5,"gold":120,"items":["やくそう","どうのつるぎ"]}

UnityではJsonUtilityを使うと、クラスのデータとJSONの文字列を簡単に行き来できます。JSONについてもっと詳しく知りたい人は、Jsonデータについて+Unityで使うJsonUtilityも読んでみてください。

保存したいデータをクラスにまとめる

using System.Collections.Generic;

[System.Serializable]
public class SaveGameData
{
    public string playerName = "勇者";
    public int level = 1;
    public int gold = 0;
    public List<string> items = new List<string>();
}
  • [System.Serializable]を付けると、JsonUtilityで変換できるようになります
  • 変換されるのはpublicの変数(または[SerializeField]を付けた変数)です
  • このクラスはMonoBehaviourではないので、ゲームオブジェクトにアタッチはしません。1つのファイル「SaveGameData.cs」として作っておきます

ファイルに保存・読み込みする

using System.IO;
using UnityEngine;

public class SaveGameManager : MonoBehaviour
{
    private string SavePath => Path.Combine(Application.persistentDataPath, "savedata.json");

    private SaveGameData data;

    void Start()
    {
        data = Load();
        Debug.Log(data.playerName + " レベル" + data.level + " 所持金" + data.gold);

        // 試しにデータを変えて保存してみる
        data.level++;
        data.gold += 50;
        data.items.Add("やくそう");
        Save();
    }

    public void Save()
    {
        // クラスのデータ → JSONの文字列 → ファイル
        string json = JsonUtility.ToJson(data, true);
        File.WriteAllText(SavePath, json);
        Debug.Log("保存しました: " + SavePath);
    }

    private SaveGameData Load()
    {
        // ファイルがまだない(初めて遊ぶ)ときは、新しいデータを使う
        if (!File.Exists(SavePath))
        {
            return new SaveGameData();
        }

        // ファイル → JSONの文字列 → クラスのデータ
        string json = File.ReadAllText(SavePath);
        return JsonUtility.FromJson<SaveGameData>(json);
    }
}

空のゲームオブジェクトにアタッチして、何回か再生してみてください。再生するたびにレベルと所持金が増えていけば、ちゃんと保存と読み込みが出来ています。

ポイント

  • JsonUtility.ToJson(データ, true):クラスをJSONの文字列にする。2つ目をtrueにすると、改行付きの読みやすい形になります
  • JsonUtility.FromJson<型>(文字列):JSONの文字列をクラスに戻す
  • Application.persistentDataPath:アプリがデータを保存してよい場所。WindowsでもMacでもスマホでも、それぞれに合った場所になります
  • Path.Combine:フォルダとファイル名を、OSに合った区切り文字でつなげる
  • File.Exists:初めて遊ぶときはファイルがないので、先に確認してから読み込みます
  • using System.IO;が必要です

保存したファイルを見てみる

ログに出た保存先のフォルダを開くと、savedata.jsonがあります。メモ帳などで開くと、JSONの中身を確認出来ます。

ファイルは普通のテキストなので、ユーザーが書き換えることも出来ます。ランキングなど、ずるをされると困るデータには、別の仕組み(サーバーでの保存など)が必要です。

よくあるエラーと対処法

エラー:保存したはずなのに、読み込むと最初の値のまま

  • 原因:PlayerPrefsのキーのつづりが、保存と読み込みで違う。またはJSONにしたいクラスに[System.Serializable]が付いていない、変数がprivateになっている
  • 対処法:キーはconstで1か所にまとめる。クラスに[System.Serializable]を付け、保存したい変数はpublicにする

エラー:The name ‘File’ does not exist in the current context

  • 原因:using System.IO;を書いていない
  • 対処法:スクリプトの一番上に足す

エラー:FileNotFoundException

  • 原因:まだ保存していないファイルを読み込もうとした
  • 対処法:File.Existsで確認してから読み込む

エラー:ArgumentException: JSON parse error

  • 原因:JSONのファイルの中身が壊れている(手で書き換えて形がおかしくなったなど)
  • 対処法:ファイルを消してやり直す。手で書き換えるときは、カッコや「,」の対応に注意する

まとめ

  • PlayerPrefs:少ない値(ハイスコア、音量など)を手軽に保存。SetInt/GetInt(キー, 既定値)
  • 大事なデータ、たくさんのデータはJSON+ファイル
  • [System.Serializable]のクラス → JsonUtility.ToJson → File.WriteAllText
  • 保存先はApplication.persistentDataPath。読み込む前にFile.Existsで確認

セーブ機能をもっと作り込みたい人は、データ保存!UnityでSave/Load機能を実装しよう!基礎編も参考にしてください。

次のステップ

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次