今回はキャラクターの持ち物の管理方法を考えます。
ゲームではアイテムを取得したり使ったりといった事を行う事がしばしばあります。
そんな時の為にアイテムをスクリプトで管理する機能を作成していきます。
アイテム管理機能
アイテムを番号で管理し、0だったらナイフの事で
1 2 3 | item[0] = true; |
等としてアイテムを持っているかどうか判断する事も出来ますが、アイテム数が増えてくると何番が何のアイテムだったか、わからなくなってきます。
持ち物管理をする為に列挙型を使う
先ほどの配列での管理ではアイテムの取得に配列番号を指定する必要がありますが、どのアイテムがどの番号か間違えなければいいですが、アイテム数が増えれば増えるほど間違いが発生します。
そんな時に列挙型を使うと番号ではなく列挙型を指定すればいいのでどのアイテムか判別するのにわかりやすくなります。
1 2 3 4 5 6 7 | public enum Item { Knife, Gun, FlashLight }; |
と宣言します。
上から順番に0、1、2のintの値と対応出来ます。
例えば
1 2 3 4 5 | // アイテムを持っているかどうかのフラグ [SerializeField] private bool[] itemFlags = new bool[6]; |
のようなフィールドを宣言し、インスペクタにアイテムフラグを表示出来るようにします。
Knifeが0番目に対応するので、ナイフを取得した場合は
1 2 3 | itemFlags [(int) Item.Knife] = true; |
とします。こうすれば0番目と指定しなくて済むので視覚的に何を取得したのかわかりやすくなります。
また他のスクリプトから特定のアイテムを持っているか?という情報がほしい場合も
1 2 3 4 5 | public bool GetItemFlag(Item item) { return itemFlags[(int) item]; } |
というゲッター関数を用意しておき、呼び出し側で
1 2 3 | GetItemFlag (MyItemStatus.Item.Gun) |
と記述すれば、ナイフを持っているかどうかの情報を得る事が出来ます。
Dictionaryを使ってアイテムの数を管理をする
列挙型とboolの配列型でアイテムを持っているかどうかを判断する事が出来ますが、列挙型とDictionaryを組み合わせるとアイテムの数を管理する事も出来ます。
Dictionaryに関しては

を参照してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using UnityEngine; using System.Collections; using System.Collections.Generic; public class ItemManager : MonoBehaviour { // アイテムの種類を設定 public enum Item { Knife, Sword, Book }; Dictionary<Item, int> itemDictionary = new Dictionary<Item, int>(); // Use this for initialization void Start () { itemDictionary [Item.Knife] = 2; itemDictionary [Item.Sword] = 3; foreach (var item in itemDictionary) { Debug.Log (item.Key + " : " + GetNum(item.Key)); } } // アイテムをどれだけ持っているかの数を返す public int GetNum(Item key) { return itemDictionary [key]; } } |
DictionaryのキーとしてItemの列挙型を指定し、値はint型でアイテムの数を設定出来るようにします。
↑の例ではStartメソッドで列挙型をキーに指定し、値を設定しています。
Dictionaryの場合はSerializeFieldやアクセス修飾子をpublicにしてもインスペクタに表示出来ません。
Dictionaryの値をインスペクタに表示するアセットを利用する
Dictionaryの値を表示したい時はUnityのアセットストアに表示する為のアセットを公開している方がいるのでそちらを使います。
アセットストアの検索でSerializableDictionaryで検索すると出てきます。
使用する場合はまずSerializableDictionaryクラスを継承した自前のクラスを用意します。
1 2 3 4 5 6 7 8 | using UnityEngine; using System.Collections; using System; [Serializable] public class ItemDictionary : SerializableDictionary<ItemManager.Item, int> {} |
↑のようにItem列挙型をキー、int型を値とするSerializableDictionaryクラスを継承しItemDictionaryクラスを定義しています。
次にアイテムを管理するスクリプトを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | using UnityEngine; using System.Collections; using System.Collections.Generic; public class ItemManager : MonoBehaviour { // アイテムの種類を設定 public enum Item { Knife, Sword, Book }; [SerializeField]public ItemDictionary itemDictionary; public IDictionary<Item, int> ItemDictionary { get { return itemDictionary; } set { itemDictionary.CopyFrom (value); } } // Use this for initialization void Start () { ItemDictionary [Item.Knife] = 0; ItemDictionary [Item.Sword] = 1; foreach (var item in ItemDictionary) { Debug.Log (item.Key + " : " + GetNum(item.Key)); } } // アイテムをいくつ持っているかどうか public int GetNum(Item key) { return ItemDictionary [key]; } } |
ItemDictionary型のシリアライズ可能なフィールドを宣言します。
itemDictionaryのプロパティのアクセサーを作成します。
Startメソッドではプロパティのアクセサーを介して値をセットしています。
これでインスペクタにキーと値が表示されるようになります。
キーと値を1セットで表示するにはエディターの拡張機能で行うしかなさそうですね・・・・。
これでキャラクターの持ち物の管理が楽になるはずです。
小さな事ですが、視覚的にわかりやすいというのは非常に重要かもしれません。
ナイフを取ったはずが懐中電灯だったという単純なバグの発生を防ぐ事が出来ます。
持ち物を管理する画面については

を参照してみてください。
アイテム管理に関してはScriptableObjectを使うとより簡単にアイテムの管理が出来るかもしれません。
