学習記事一覧 · Unity

【学習】Unity:アイテム所持とセーブ入門(第4回)― どこからでも使う:OwnedItemsDataInstance

第3回 までで、JSON + PlayerPrefs の考え方は揃いました。

しかしゲームのコードは、シーンのどこからでも「今の所持数」を触りたくなります。

  • 敵を倒した
  • 宝箱を開けた
  • UI のボタンを押した

このとき 同じデータを共有したい。

今回は データ専用のクラスInstance(教材では「入口が 1 つ」)を置くパターンを整理します。書籍サンプルでは OwnedItemsData がこの役です。

シリーズ


今日のゴール

  • MonoBehaviour ではない「所持データ」の方が、保存と共有に向く理由が言える
  • Instance に触れば同じオブジェクトを参照できる(教材レベルの理解)
  • PlayerPrefs.HasKey … あれば FromJson、なければ new が書ける
  • Save()JsonUtility.ToJson(this)SetString の流れを追える

なぜ MonoBehaviour から切り離す?

役割 MonoBehaviour データ専用クラス
シーンに張り付く 前提 不要
JsonUtility で丸ごと保存 罠になりやすい 相性がよい
「どこからでも触る」 FindObjectOfType などが必要になりがち Instance で集約しやすい

授業では 「JSON にしたい中身はデータ側に寄せる」 と決めると迷いが減ります。


OwnedItemsData の骨格(読み取りのポイント)

次の 4 点がわかれば、まずは十分です。

  1. [Serializable] … JSON 化の前提
  2. Instance … 初回アクセスで 保存があれば復元/なければ新規
  3. List<OwnedItem> ownedItems … 第2回と同型の「集まり」
  4. Save()JsonUtility.ToJson(this)自分全体を文字列化して PlayerPrefs

ざっくりした形(教材用・骨格イメージ)

using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class OwnedItemsData
{
    private const string PlayerPrefsKey = "OWNED_ITEMS_DATA";
    public static OwnedItemsData Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = PlayerPrefs.HasKey(PlayerPrefsKey)
                    ? JsonUtility.FromJson<OwnedItemsData>(PlayerPrefs.GetString(PlayerPrefsKey))
                    : new OwnedItemsData();
            }
            return _instance;
        }
    }
    private static OwnedItemsData _instance;
    [SerializeField] private List<OwnedItem> ownedItems = new List<OwnedItem>();
    private OwnedItemsData() { }
    public void Save()
    {
        string json = JsonUtility.ToJson(this);
        PlayerPrefs.SetString(PlayerPrefsKey, json);
        PlayerPrefs.Save();
    }
    // Add / Use / GetItem …(第2回の考え方と同じ)
}

実装の詳細(OwnedItem のネスト、FirstOrDefaultUse で例外を投げる等)は、手元のサンプルいきのこバトル:所持品データとオーディオ の全文と照らし合わせてください。


プログラムの流れ

ゲーム起動

初めて Instance に触る

セーブがあれば FromJson で復元/なければ new

プレイ中に Add / Use

タイミングを決めて Save()

重要ポイント

  • private コンストラクタ … 外部の new OwnedItemsData() を減らし、生成ルートを Instance に寄せる(教材としての狙い)
  • 保存キーは定数にまとめる(スペルミス防止)
  • 毎フレーム Save は重い・壊れやすいので、授業では 取得直後・ステージクリア・メニュー閉じなど イベント単位を推奨

教材向けの一言

ここでこう言うと理解が進みます。

「JSON は、オブジェクトの状態を文字列にしたもの。だから保存したい状態は、まずデータのクラスに集約する」


発展アイデア

  • OOP:シングルトンパターン本書の 3 パターン(純 C# / DontDestroyOnLoad 等)を比較する
  • テスト用に DeleteAll との付き合い方(開発ビルドだけ、など)を決める

次に進む

データの出入り口ができたので、フィールドのオブジェクトから Add して Save する流れをつなぎます。

第5回:Item 取得からセーブまで