2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

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

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?