シンプルなアイテム管理システムの作り方

前回の作業でマウスオーバーを検知する処理を作ることができました。次は「オブジェクトを調べる」処理を作りたいところですが、その前にまだ準備しておきたいことがあります。

それは「アイテム管理システム」(=いわゆるインベントリ)です。脱出ゲームでは何かを調べた時にアイテムを見つけたり使ったりすることが多いので、ここでは先にその仕組みを作ってしまいましょう。


※今回の脱出ゲームでは複雑なアイテム管理システムは必要ないので、最低限の機能を持ったインベントリを作ります。

スポンサーリンク

インベントリ用のUIの作成

まずはインベントリ用のUIを用意します。

キャンバスを用意する

以前説明したのと同じ要領でシーンに新しいキャンバスを作り、その子としてからのゲームオブジェクトを作ります。

そうしたらそのゲームオブジェクト(※「Item Parent」とします)に「Horizontal Layout Group」コンポーネントをアタッチして、次のように設定しましょう。

Horizontal Layout Groupの設定例

アイテムのアイコンのプレハブを作る

次にアイテムのアイコンのプレハブを作ります。右クリックメニューから「UI」→「画像」を選び、新しいImageオブジェクトを作ったらサイズを48×48にして、適当なフォルダにドラッグ&ドロップしてプレハブ化してください。

ちなみに画像は後でスクリプトから変更するので設定する必要はありません。

アイテム管理システムのC#スクリプト

では次にアイテム管理システムのC#スクリプトを書いていきます。新しいC#スクリプトを作り、名前を「SimpleInventory」に変更して次のコードを書いてください。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SimpleInventory : MonoBehaviour
{
  
  [SerializeField]
  GameObject iconPrefab = null;
  [SerializeField]
  Transform iconParent = null;
  [SerializeField]
  InventoryItem[] items = null;

  // アイテムを持ってるかどうかのフラグ
  bool[] itemFlags;

  // アイテムのアイコンを管理するためのディクショナリ
  Dictionary<int, GameObject> icons = new Dictionary<int, GameObject>();

  void Start()
  {
    itemFlags = new bool[items.Length];
  }

  // アイテムを持ってるかどうかを確認するメソッド
  public bool GetItemFlag(string itemName)
  {
    int index = GetItemIndexFromName(itemName);

    return itemFlags[index];
  }

  public void SetItem(string itemName, bool isOn)
  {
    int index = GetItemIndexFromName(itemName);

    if (!itemFlags[index] && isOn)
    {
      // アイテム未所持の状態で新しく入手したとき
      // 新しいアイコンを生成し、インベントリのキャンバスの子に設定
      GameObject icon = Instantiate(iconPrefab, iconParent);

      // アイコンの画像を設定
      icon.GetComponent<Image>().sprite = items[index].itemSprite;

      icons.Add(index, icon);
    }
    else if(itemFlags[index] && !isOn)
    {
      // アイテム所持中に削除するとき

      GameObject icon = icons[index];

      // アイテムのアイコンを削除
      Destroy(icon);

      // アイコンのディクショナリから対象のアイテムを削除
      icons.Remove(index);
    }

    itemFlags[index] = isOn;
  }

  int GetItemIndexFromName(string itemName)
  {
    for(int i = 0; i < items.Length; i++)
    {
      if(items[i].itemName == itemName)
      {
        return i;
      }
    }

    Debug.LogWarning("指定されたアイテム名が間違っているか存在しません");

    return 0;
  }

}

// インベントリに登録できるアイテムを定義するためのクラス
[System.Serializable]
public class InventoryItem
{

  public string itemName = "";
  public Sprite itemSprite = null;

}

初心者の方には少し難しいかもしれないので解説をしておきますね。

スクリプトの解説

まず、インベントリを実現するためには次の2つの処理をやる必要があります。

  1. アイテムを持っているかどうかを判定する処理
  2. アイテムの有無に合わせてアイコンを表示・非表示する処理

そこでここでは1.を管理するためにbool型の配列「itemFlags」、2.を管理するためにディクショナリ型の「icons」を用意しました。iconsの役割はちょっと分かりづらいのですが、このディクショナリは

  • キーにアイテムのID(ここではインデックス)
  • 値にゲームオブジェクトの参照

を持っていて、アイテムそのもののデータと「アイテムのアイコンを表示するためのゲームオブジェクト」の対応関係を保持します。こうすることで、例えばアイテムAを削除したときに「アイテムAのアイコン」も狙い撃ちで削除できるようにしているというわけです。これが分かれば、あとはコメントを読んでもらえばスクリプトの処理をおおよそ理解していただけると思います。

それから下の方に書いてあるクラス「InventoryItem」の役割も補足しておくと、これはコメントの通りでインベントリに登録できるアイテムを定義するクラスです(※注)。

今回の脱出ゲームではアイテムの種類がごく限られているので、インベントリに登録できるアイテムをあらかじめ決めておくことにしました。そしてそのためにアイテム名とアイテム画像を登録できる欄が欲しかったので、このように新しいクラスを定義してその配列を作ることにした…というわけです。


※注:初心者の方はご存じない場合が多いので書いておくと、実はUnityでは上記のように自分で勝手にクラスを追加して使うことが可能です(まあ考えてみれば当然の話ですが…)。ただしその場合は

  • Monobehaviourを継承していないクラスはゲームオブジェクトにアタッチできない
  • クラスに[System.Serializable]属性をつけないとシリアライズできない

という点には注意してください。

スクリプトのアタッチ&設定

さてスクリプトを書いたら、それを適当なゲームオブジェクトにアタッチして設定を行います。ここでは新しいゲームオブジェクト「Inventory」を作り、そこに上記のスクリプトをアタッチすることにしました。

設定については下記のようにしてください。

  • Icon Prefab:先ほどの作業で作ったアイコンのプレハブを登録
  • Icon Parent:同じく先ほどの作業で作った「Item Parent」を登録
  • Items:脱出ゲームに必要なアイテムを好きなように登録

これでシンプルなアイテム管理システムができました。とはいえまだ前回のエラーが直っていないと思うのでテストプレイできません。次回まとめてテストすることにしましょう。


次のページ→脱出ゲームのオブジェクトを調べる処理の作り方