スポンサーリンク
UnityUnityメモ

【実践】UnityでJSONデータ管理!セーブ&ロードを最適化する方法

Unity

1. はじめに

ゲームを作っていると「スコアを保存したい」「次に遊ぶときに進行状況を読み込みたい」と思う瞬間ってありますよね。特にRPGのセーブデータやアクションゲームのハイスコアなど、プレイヤーのデータをしっかり保存・管理する仕組みは欠かせません。

そんなときに便利なのが、JSON(JavaScript Object Notation)というデータ形式です。JSONは人間にも読みやすく、キーと値のペアで情報を整理できるため、ゲームデータの保存にぴったり。UnityではJsonUtilityを使えば、クラスとJSONの変換(シリアル化・デシリアル化)がとても簡単に行えます。

この記事では、UnityでJSONを使ったセーブ&ロードの方法を、初心者の方にもわかりやすく解説していきます。スコアやランキングを例に、保存・読み込み・削除までの流れをステップごとに紹介。さらに、効率的なデータ管理に役立つアセットや実践的なポイントもあわせて解説します。

C#の基礎をしっかり押さえておくと、スクリプト実装がグッと理解しやすくなります。もし「もっとC#を学んでから実装したい!」という方は、こちらの書籍がおすすめです。

ではさっそく、UnityでのJSONデータ管理の基礎から見ていきましょう!


2. JSONデータ管理の基礎

まずは、UnityでJSONを扱うときに必要な基礎知識を押さえておきましょう。ここでは「シリアル化」「デシリアル化」といったキーワードや、データ保存の基本的な流れについて解説します。

2-1. JsonUtilityとは?

UnityにはJsonUtilityという便利なクラスが用意されています。これはオブジェクト(クラスのインスタンス)をJSON形式の文字列に変換したり、逆にJSON文字列をオブジェクトに戻したりする機能を持っています。
例えば、以下のように使えます:


// クラスをJSONに変換
string json = JsonUtility.ToJson(myData);

// JSONをクラスに戻す
MyData loadedData = JsonUtility.FromJson<MyData>(json);

これだけで「保存用データ ↔ JSON文字列」の変換が可能になるので、ファイル保存の仕組みと組み合わせれば簡単にセーブ&ロードが作れます。

2-2. シリアル化可能なクラスを作る

JsonUtilityでデータを扱うには、保存対象のクラスを[System.Serializable]属性でマークしておく必要があります。例えば、スコアを保存する場合は次のようになります:


[System.Serializable]
public class SaveData {
    public int maxScore;
}

このようにすれば、maxScoreをJSONファイルに書き出したり、読み込んだりできるようになります。
補足ですが、private変数を保存したいときは[SerializeField]を付けてあげるとOKです。

2-3. 保存先のパスを知っておこう

JSON文字列をファイルに保存するには、書き込み先のパスが必要です。Unityでは、Application.persistentDataPathという変数でユーザーごとのセーブデータ保存先を取得できます。
例:Windowsの場合は以下のようなフォルダに保存されます。


C:\Users\ユーザー名\AppData\LocalLow\会社名\プロジェクト名

このフォルダはゲームを再起動しても消えないので、セーブデータの保存先としてよく利用されます。開発中のデバッグで一時的に保存する場合はApplication.dataPathを使うこともあります。

ここまでで「JSONに変換する準備」「保存できるフォルダ」が揃いました。次のステップでは、実際にセーブ/ロード/削除を行う仕組みを作っていきましょう!




3. 実装方法A:汎用的なセーブ/ロード/削除システム

ここからは実際に「スコアの最大値(MaxScore)」を例にして、セーブ・ロード・削除ができる汎用的な仕組みを作っていきます。シーンをまたいでも使えるように、データ管理と保存処理を分けて設計するのがポイントです。

3-1. クラス設計

まずは今回の仕組みに必要なクラスを整理してみましょう。

クラス名役割
SaveData保存したいデータ(例:maxScore)を保持する。
[System.Serializable]が必要。
SavedDataStore読み込んだデータを保持するstaticクラス。
UI更新用にUnityEventを持たせる。
SaveAndLoadSystem<T>ジェネリック型を使ったセーブ・ロード・削除の仕組みを提供。
SaveAndLoadButtonボタン操作用。セーブ・ロード・削除を呼び出す。
ScoreManagerスコアの加算、最大値の更新、UI表示を管理。

3-2. セーブの実装

まずは「スコアを更新したら保存する」という流れを作ります。


[System.Serializable]
public class SaveData {
    public int maxScore;
}

public static class SaveAndLoadSystem&lt;T&gt; {
    public static void Save(T data, string fileName) {
        string json = JsonUtility.ToJson(data);
        string path = Path.Combine(Application.persistentDataPath, fileName + ".json");
        File.WriteAllText(path, json);
    }
}

SaveAndLoadSystem.Save()を呼ぶと、自動的にJSONファイルとして保存されます。スコアが更新されたタイミングでこの処理を呼び出せばOKです。

3-3. ロードの実装

次に、保存したデータを読み込む仕組みを作ります。


public static T Load(string fileName) {
    string path = Path.Combine(Application.persistentDataPath, fileName + ".json");
    if (!File.Exists(path)) return default;

    string json = File.ReadAllText(path);
    return JsonUtility.FromJson&lt;T&gt;(json);
}

これで、ゲーム開始時やロードボタンを押したときにデータを復元できます。UIに反映したい場合は、ロードが完了したタイミングでUnityEventを呼び出すと便利です。

3-4. 削除の実装

セーブデータをリセットしたいときは削除処理を用意しておきましょう。


public static void Delete(string fileName) {
    string path = Path.Combine(Application.persistentDataPath, fileName + ".json");
    if (File.Exists(path)) {
        File.Delete(path);
    }
}

これで「セーブ」「ロード」「削除」がひととおり揃いました。UIのボタンと連動させれば、誰でもわかりやすいセーブシステムを構築できます。

💡さらに便利にしたい方は、Inspector上でデータを直感的に編集できるOdin Inspector and Serializerを使うと、セーブデータの中身を視覚的に管理できて開発効率が大きくアップします。


4. 実装方法B:ランキングシステムの構築

次は、ランキングデータをJSONで保存・管理する方法を紹介します。プレイヤーのスコアを順位付きで保存して、次回プレイ時に読み込む仕組みを作ってみましょう。

4-1. クラス設計

ランキング管理では、以下のようなクラスを用意します。

クラス名役割
SaveDataランキングスコア(例:int配列 rank[])を保持。
DataManagerファイルI/O処理とデータ保持を担当。Awakeでロード、OnDestroyで自動セーブ。
Rankingスコアを入力し、ランキング更新やUI表示を行う。

4-2. データの初期化とロード

ゲーム開始時にセーブデータが存在するか確認し、なければ初期化します。存在すればロードしてランキングを復元します。


[System.Serializable]
public class SaveData {
    public int[] rank = new int[5];
}

public class DataManager : MonoBehaviour {
    public SaveData data;
    string filePath;

    void Awake() {
        filePath = Path.Combine(Application.persistentDataPath, "ranking.json");

        if (File.Exists(filePath)) {
            string json = File.ReadAllText(filePath);
            data = JsonUtility.FromJson&lt;SaveData&gt;(json);
        } else {
            data = new SaveData();
            Save();
        }
    }

    public void Save() {
        string json = JsonUtility.ToJson(data);
        File.WriteAllText(filePath, json);
    }

    void OnDestroy() {
        Save();
    }
}

この仕組みにより、ゲーム終了時には自動的にセーブされ、次回起動時にはランキングが復元されます。



4-3. ランキング更新

新しいスコアを入力して、ランキングの配列に挿入する処理を作成します。


public class Ranking : MonoBehaviour {
    public DataManager dataManager;
    public TMPro.TextMeshProUGUI[] rankTexts;

    public void SetRank(int newScore) {
        int[] rank = dataManager.data.rank;
        for (int i = 0; i &lt; rank.Length; i++) {
            if (newScore &gt; rank[i]) {
                // スコアを挿入してシフト
                for (int j = rank.Length - 1; j &gt; i; j--) {
                    rank[j] = rank[j - 1];
                }
                rank[i] = newScore;
                break;
            }
        }
        dataManager.Save();
        UpdateUI();
    }

    void UpdateUI() {
        for (int i = 0; i &lt; rankTexts.Length; i++) {
            rankTexts[i].text = dataManager.data.rank[i].ToString();
        }
    }
}

これで新しいスコアが従来のランキングを上回った場合、自動的に順位が更新されます。

4-4. ランキングのリセット

データを初期化してリセットしたい場合は、配列をすべて0にして保存します。


public void ResetRanking() {
    for (int i = 0; i &lt; dataManager.data.rank.Length; i++) {
        dataManager.data.rank[i] = 0;
    }
    dataManager.Save();
    UpdateUI();
}

💡 ランキング処理のように「データが正しく保存・読み込めているか」をチェックしたいときは、Editor Console Proを使うと、ログ検索やフィルタリングが楽になり、デバッグ効率が大幅にアップします。


5. セキュリティと実践的な注意点

JSONを使ったセーブ&ロードはとても便利ですが、実際にゲームとして公開する場合にはいくつか注意すべき点があります。ここでは代表的なものを紹介します。

5-1. データ改ざん対策

JSONファイルはテキスト形式のため、ユーザーが直接書き換えてしまう可能性があります。例えば「スコアを999999に書き換える」といった不正行為が起きかねません。
対策としては以下のような方法があります:

  • セーブデータを暗号化して保存する
  • セーブ時にハッシュ値(署名)を追加して改ざんチェックする
  • サーバーと通信してオンライン保存する

カジュアルゲームなら簡易的な暗号化、ランキングが重要なオンラインゲームならサーバー保存が一般的です。

5-2. ScriptableObjectの取り扱い

UnityのScriptableObjectは便利な仕組みですが、そのままではJsonUtilityでシリアル化できません。
その場合は「一度専用のクラスにデータをコピーしてからJSONに変換する」といった工夫が必要です。特にアイテムデータやキャラクター設定を扱うときは注意しましょう。

5-3. 自動セーブの導入

プレイヤーが手動で「セーブボタン」を押すのを忘れてしまうこともあります。そんなときのために、以下のようなタイミングで自動セーブを行うのも効果的です。

  • ステージクリア時
  • アプリ終了時(OnApplicationQuitやOnDestroyで保存)
  • 一定間隔ごと(コルーチンで定期セーブ)

ただし自動セーブを多用するとパフォーマンスに影響する場合もあるため、ゲームの規模やプレイスタイルに合わせて調整しましょう。

セーブ・ロード機能はバグが出やすい部分でもあります。保存パスの確認やファイルの存在チェックなどをしっかり入れておくと安心です。
また、コンソールログをフィルタリングできるツールを導入すると、デバッグがスムーズになります。




6. まとめ

今回は、UnityでJSONを使ってデータをセーブ・ロード・削除する方法を解説しました。記事の内容を振り返ると次のようになります。

  • JsonUtilityを使えば、クラス ⇔ JSON変換(シリアル化・デシリアル化)が簡単にできる
  • 保存先はApplication.persistentDataPathを使うのが基本
  • 実装方法Aでは、スコアの最大値を例に「汎用的なセーブ/ロード/削除」を構築
  • 実装方法Bでは、ランキングシステムを例に「自動セーブ&復元」を実装
  • 実際のゲーム公開時には、改ざん防止や暗号化、自動セーブの工夫が必要

JSONはテキスト形式で扱いやすいので、初心者でも比較的導入しやすいデータ保存方法です。小さなスコア保存から、ランキングやゲーム進行度のセーブまで幅広く活用できるので、ぜひご自身のプロジェクトでも試してみてください。

さらに効率よく開発したい方は、データ管理を強化できるアセットを導入するのもおすすめです。
Odin Inspector and Serializer
Editor Console Pro

セーブ&ロードは「ゲームの遊びやすさ」に直結する大事な部分です。基礎を理解して仕組みを作れるようになると、ゲーム開発の幅がぐっと広がりますよ!


あわせて読みたい

今回紹介したJSONデータ管理以外にも、Unityでのデータ保存や管理に役立つ記事をまとめました。あわせて読むことで、より幅広い知識が身につきますよ!


よくある質問(FAQ)

Q
JSONとPlayerPrefsはどう使い分ければいいですか?
A

PlayerPrefsは「音量設定」「操作設定」など軽量なデータの保存に便利です。一方でJSONは「セーブデータ」「ランキング」など複雑な構造を持つデータに向いています。
シンプルなデータはPlayerPrefs、ゲーム進行やランキングのように多くの値を扱う場合はJSONがおすすめです。

Q
保存したJSONファイルをユーザーに見られないようにするには?
A

JSONファイルはテキスト形式なので、そのままでは簡単に編集されてしまいます。セキュリティを高めたい場合は暗号化難読化を行うとよいでしょう。さらに競技性のあるゲームでは、サーバーと通信してスコアを保存する方法が一般的です。

Q
モバイルアプリでも同じように使えますか?
A

はい、同じ仕組みが使えます。Application.persistentDataPathはiOSやAndroidでも環境に合わせた適切な保存先を返すため、特別なコード変更なしでセーブ&ロードが可能です。
ただし、プラットフォームによっては書き込み権限に制限がある場合があるので、実機テストで確認するのが安心です。

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク