Unity × JSONファイル運用の落とし穴

Unity

PlayerPrefsではなくJSON保存に切り替えるときに知っておきたい制約と実装Tips

はじめに

Unityでのデータ永続化にはPlayerPrefsが手軽に使えますが、より柔軟なデータ構造や複数項目をまとめて管理したい場面ではJSONファイル保存が便利です。

私自身も開発中のプロジェクトでPlayerPrefsからJSONベースの保存方式に移行しましたが、その中でUnity標準のJsonUtilityには予想外の制約がいくつも存在することに気付きました。本記事では、それら制約とその回避方法を解説します。

UnityにおけるJSON運用の基本

Unityでは以下の2種類のJSON変換手段が一般的です:

  • JsonUtility(Unity標準)
  • Newtonsoft.Json(外部ライブラリ。通称:Json.NET)

このうち、JsonUtilityは軽量で依存関係が不要な反面、扱えるデータ構造に多くの制限があります。

JsonUtilityの制約とその対処法

以下はUnity標準のJsonUtilityを使った場合に遭遇した代表的な制約です。

1. Dictionaryが保存できない

[System.Serializable]
public class SaveData
{
    public Dictionary<string, int> scoreDict; // ×JsonUtilityでは保存不可
}

回避策

  • 独自のシリアライズ可能なSerializableDictionaryを使う
  • 保存時にList<KeyValuePair<string, int>>などに変換して書き出す

2. 抽象型や継承型の保存ができない

[System.Serializable]
public class Animal { public string name; }
public class Dog : Animal { public int barkPower; }

public class Zoo {
    public Animal myPet; // 実体がDogでもbarkPowerは保存されない
}

回避策

  • 継承を避け、明示的にすべての型情報を持つ構造に分解する
  • Json.NETに切り替えてTypeNameHandlingオプションで対応

3. ListのListが保存できない

[System.Serializable]
public class GridData
{
    public List<List<int>> mapGrid; // ×Unityでは失敗することが多い
}

回避策

  • List<Row>のような中間クラスを設ける
[System.Serializable] public class Row { public List<int> columns; }
[System.Serializable] public class GridData { public List<Row> rows; }

4. private変数、[NonSerialized]変数は保存されない

[System.Serializable]
public class SaveData {
    private int hiddenValue; // ×保存されない
}

対策

  • public + [SerializeField]が必要
  • UnityのInspectorと同じルールが適用される

実装パターン例:JSONの読み書きを一元化する

public static class JsonSaveManager
{
    public static void Save<T>(string fileName, T data)
    {
        string json = JsonUtility.ToJson(data);
        string path = Path.Combine(Application.persistentDataPath, fileName);
        File.WriteAllText(path, json);
    }

    public static T Load<T>(string fileName)
    {
        string path = Path.Combine(Application.persistentDataPath, fileName);
        if (!File.Exists(path)) return default;
        string json = File.ReadAllText(path);
        return JsonUtility.FromJson<T>(json);
    }
}

保存ファイルの場所に注意

  • Application.persistentDataPath:各プラットフォームで安全に保存可能
  • Android/iOSで確認する場合はadbやXcodeでログ確認・ファイル出力が必要

まとめ

  • Unity標準のJsonUtilityは軽量ですが制限が多い
  • 複雑な構造を扱うならJson.NETも検討価値あり
  • 保存対象の構造体はシンプル・publicフィールドベースに保つと安全
  • 保存・読み込みはラップクラスで一元化すると管理しやすい

ブログでもUnityや個人開発ネタを発信中です!

開発ノウハウやアプリ制作過程、Unity連携系のハマりポイントなど
より深掘りした内容をブログにまとめています。
https://syunpp.com

公開中のアプリ一覧はこちら!

実際にUnityで開発してリリース済みのアプリ一覧をまとめています。
https://syunpp.com/公開中のアプリ一覧/

YouTubeショートでもゲーム開発の裏側を公開中!

Unityで制作中のゲームの進捗や演出テスト、実装の様子を
ショート動画でタイムラプス形式にまとめて発信しています。
https://www.youtube.com/@syunpp_8413/shorts

コメント

タイトルとURLをコピーしました