Unity のアイテム管理システム:OwnedItemsData と Item クラスの完全解説

このシステムは、プレイヤーが所持するアイテムの情報を保存・管理するための OwnedItemsData クラスと、実際のゲームオブジェクトとしてのアイテムの生成・アニメーション、さらにプレイヤーとの衝突時にアイテムを回収するための Item クラスで構成されています。以下、各部分の詳細とサンプルコードを交えながら解説します。


1. OwnedItemsData クラスの詳細

1-1. クラスの概要

目的:

  • プレイヤーの所持アイテム(例:ポーション、木、石、投げオノなど)を一元管理する。
  • ゲーム再起動後もデータが残るように、PlayerPrefs と JSON による永続化を実現。

主要な機能:

  • シングルトンパターン:
    どこからでも同じデータにアクセスできるように、クラスはインスタンスを一つだけ生成します。
  • データの永続化:
    現在のアイテム情報を JSON 形式に変換して PlayerPrefs に保存します。
  • アイテムの追加/消費:
    指定されたアイテムの個数を増加(Add)または減少(Use)させる処理が実装されています。

1-2. サンプルコードと解説

・ シングルトンとデータの読み込み/保存

public class OwnedItemsData
{
    // 保存先のキー
    private const string PlayerPrefsKey = "OWNED_ITEMS_DATA";

    // シングルトン用インスタンス
    private static OwnedItemsData _instance;
    public static OwnedItemsData Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = PlayerPrefs.HasKey(PlayerPrefsKey)
                    ? JsonUtility.FromJson<OwnedItemsData>(PlayerPrefs.GetString(PlayerPrefsKey))
                    : new OwnedItemsData();
            }
            return _instance;
        }
    }

    // 所持アイテム一覧
    [SerializeField] private List<OwnedItem> ownedItems = new List<OwnedItem>();

    // プロパティで配列として取得可能
    public OwnedItem[] OwnedItems { get { return ownedItems.ToArray(); } }

    // コンストラクタは private にして外部から new できないように
    private OwnedItemsData() { }

    // 現在の状態を JSON に変換して PlayerPrefs に保存
    public void Save()
    {
        var jsonString = JsonUtility.ToJson(this);
        PlayerPrefs.SetString(PlayerPrefsKey, jsonString);
        PlayerPrefs.Save();
    }
}

・ アイテムの追加・消費とアイテム取得

public void Add(Item.ItemType type, int number = 1)
{
    var item = GetItem(type);
    if (item == null)
    {
        item = new OwnedItem(type);
        ownedItems.Add(item);
    }
    item.Add(number);
}

public void Use(Item.ItemType type, int number = 1)
{
    var item = GetItem(type);
    if (item == null || item.Number < number)
    {
        throw new Exception("アイテムが足りません");
    }
    item.Use(number);        
}

public OwnedItem GetItem(Item.ItemType type)
{
    return ownedItems.FirstOrDefault(x => x.Type == type);
}

・ 個々のアイテム情報を管理する内部クラス:OwnedItem

[Serializable]
public class OwnedItem
{
    [SerializeField] private Item.ItemType type;
    public Item.ItemType Type => type;

    [SerializeField] private int number;
    public int Number => number;

    // アイテムの種類を指定して初期化
    public OwnedItem(Item.ItemType type)
    {
        this.type = type;
    }

    // 指定数だけ追加
    public void Add(int number = 1)
    {
        this.number += number;
    }

    // 指定数だけ減少
    public void Use(int number = 1)
    {
        this.number -= number;
    }
}

2. Item クラスの詳細

2-1. クラスの概要

目的:

  • ゲームワールド上のアイテム(木、石、投げオノなど)として機能する。
  • 出現時にアニメーション(移動とスケール変更)を実行し、アニメーション完了後にアイテムの Collider を有効化。
  • プレイヤーの接触を検知し、衝突時に該当アイテムを OwnedItemsData に追加してから、アイテムオブジェクトを破棄する。

特徴:

  • RequireComponent:
    Collider コンポーネントが必須であることを明示する属性を使用。
  • DG.Tweening:
    DOTween を利用して、出現時の連続アニメーション(移動・スケール)を実装。

2-2. サンプルコードと解説

using DG.Tweening;
using UnityEngine;

[RequireComponent(typeof(Collider))]
public class Item : MonoBehaviour
{
    /// <summary>
    /// アイテムの種類を列挙
    /// </summary>
    public enum ItemType
    {
        Wood,     // 木
        Stone,    // 石
        ThrowAxe  // 投げオノ(木と石で作る!)
    }

    // インスペクター上で種類を設定 (例: Wood / Stone / ThrowAxe)
    [SerializeField] private ItemType type;

    /// <summary>
    /// 初期化処理
    /// - 出現アニメーションを実行
    /// - アニメーション完了まではColliderを無効化
    /// </summary>
    public void Initialize()
    {
        Collider colliderCache = GetComponent<Collider>();
        colliderCache.enabled = false;

        // 出現位置をランダムにずらす
        Transform transformCache = transform;
        Vector3 dropPosition = transformCache.localPosition +
                               new Vector3(Random.Range(-1f, 1f), 0f, Random.Range(-1f, 1f));

        // DOTweenのSequenceで移動とスケールを連続アニメーション
        Sequence sequence = DOTween.Sequence();

        // 移動: 0.5秒かけてランダム座標へ
        sequence.Append(transformCache.DOLocalMove(dropPosition, 0.5f));

        // スケール: ゼロから元の大きさへ (Ease.OutBounceで弾むような演出)
        Vector3 defaultScale = transformCache.localScale;
        transformCache.localScale = Vector3.zero;
        sequence.Append(transformCache.DOScale(defaultScale, 0.5f).SetEase(Ease.OutBounce));

        // アニメーション完了後にColliderを有効化
        sequence.OnComplete(() =>
        {
            colliderCache.enabled = true;
        });
    }

    /// <summary>
    /// プレイヤーとの衝突判定
    /// </summary>
    /// <param name="other">衝突したCollider</param>
    private void OnTriggerEnter(Collider other)
    {
        // タグが "Player" でなければ処理を行わない
        if (!other.CompareTag("Player")) return;

        // アイテムをプレイヤーの所持データに追加し、保存する
        OwnedItemsData.Instance.Add(type);
        OwnedItemsData.Instance.Save();

        // 現在の所持アイテムの状態をログに出力
        foreach (var item in OwnedItemsData.Instance.OwnedItems)
        {
            Debug.Log($"{item.Type}を{item.Number}個所持");
        }

        // このアイテムオブジェクトを破棄
        Destroy(gameObject);
    }
}

解説:

  • Initialize メソッド:
  • Collider の無効化: アニメーション実行中は当たり判定を外すため、Collider を一時的に無効化します。
  • 位置とスケールのアニメーション:
    • 出現時にアイテムがランダムな位置に移動し、ゼロのスケールから元の大きさへと拡大する連続アニメーションを実行します。
    • アニメーション完了後、Collider を再度有効にします。
  • OnTriggerEnter メソッド:
  • プレイヤー(タグ “Player")が接触したとき、OwnedItemsData の Add メソッドを呼び出して該当アイテムを追加。
  • アイテム取得後、データを保存し、所持アイテムの一覧をログ出力します。
  • 最後に、取得済みのアイテムオブジェクトをシーンから削除(Destroy)します。

3. システムの全体の流れと統合

全体のステップ

  1. アイテムオブジェクトの生成と初期化:
  • シーン内に配置された各 Item オブジェクトは、Initialize() メソッドを呼び出すことで、DOTween を使った出現アニメーションを実行します。
  • アニメーション中は Collider が無効となり、プレイヤーとの不要な衝突を防ぎます。
  1. プレイヤーとの衝突検知:
  • プレイヤーがアイテムに接触すると、OnTriggerEnter メソッドが呼ばれ、対象のアイテムが OwnedItemsData に追加されます。
  • アイテム取得後、所持情報が保存され、デバッグ用に現在のアイテム一覧がログに出力されます。
  1. データの永続化と管理:
  • OwnedItemsData はシングルトンパターンによりどこからでもアクセスでき、一度取得したアイテムの情報は PlayerPrefs を使用して永続的に保存されます。

統合利用例 (GameManager からの呼び出し例)

public class GameManager : MonoBehaviour
{
    void Start()
    {
        // シーン内のアイテム初期化(場合によっては各アイテムの Start や Awake 内で呼び出す)
        Item[] items = FindObjectsOfType<Item>();
        foreach (Item item in items)
        {
            item.Initialize();
        }
    }
}

このような流れにより、ゲーム内でアイテムの出現、プレイヤーとの接触、及びその後のデータ管理までがシームレスに連携されます。


4. まとめ

本システムは、次の要素を組み合わせた Unity のアイテム管理の実例です:

  • OwnedItemsData クラス:
    • シングルトンパターンで一元管理し、PlayerPrefs と JSON による永続化でデータ保持を実現。
    • アイテムの追加、消費、取得を通じて、プレイヤーの所持情報を管理します。
  • Item クラス:
    • 実際のゲームオブジェクトとして機能し、DG.Tweening を用いた出現アニメーションやプレイヤーとの衝突処理を実装。
    • 衝突時にアイテムを取得し、OwnedItemsData に反映、その後アイテムオブジェクトを破棄することで取得処理が完了します。

この一連の仕組みにより、プレイヤーがゲーム中にアイテムを取得するシンプルかつ効果的なシステムが実現されます。各コード例を実際に動作させながら理解を深めることで、Unity におけるデータ管理とゲームオブジェクトの連携方法についての知識が広がるでしょう。

Unity

Posted by hidepon