今回はUnityで持ち物画面を作成したいと思います。
ゲーム中に中断している時にポーズ用のUIを表示する代わりに持ち物画面を表示します。
全部の持ち物分のスロット(入れ物)を用意して、持っているアイテムの種類を表すアイコンを表示します。
スロットの上にマウスをがきたら情報欄にそのアイテムの情報を表示します。
今回作成する持ち物画面はマウス操作で実行しますので、ゲームパッドやキー操作出来る持ち物画面を作りたい方は
を参照してください。
持ち物画面UIを作成
まずはPropertyUIという名前でUIを作成していきます。
Canvasを作成しPropertyUIという名前に変更し、子要素にPanel、その子要素にPanelを3つ作成し、Title、Main、Informationという名前にします。
TitleとInformationの子要素にUIのTextを作成します。
Titleの子要素のTextコンポーネントのTextには持ち物画面のタイトル名を入れておきます。
上のようにTitle、Main、Information(色ごとに分けてあります)という順になるように領域を調整します。
名前やレイアウトは自由に変更してください。
Mainのインスペクタを表示し、Add ComponentからLayout→Grid Layoutを選択します。
Cell Sizeで横幅と縦幅を指定します。Spacingでセル間の距離を指定します。
Start Cornerはどこから最初のセルを表示するか
Start Axisは縦と横のどちらにセルを並べていくか
Child Alignmentは子要素の並び位置
Constraintsは行と列の数に制限を持たせる
という設定になります。
今回は上の画像のように設定しました。
アイテムクラスItemDataとアイテム情報管理スクリプトItemDataBaseを作成
次にアイテムの情報を管理する為に、ItemDataスクリプトとアイテムの情報を保存しておくItemDataBaseスクリプトを作成します。
今回はスクリプト上でアイテム情報の生成をしていますが、ScriptableObjectを使ってあらかじめアイテムデータファイルとアイテムデータベースを作成しておく方がわかりやすいです。
ItemDataというスクリプトを作成します。
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 39 | using UnityEngine; using System.Collections; public class ItemData { // アイテムのImage画像 private Sprite itemSprite; // アイテムの名前 private string itemName; // アイテムのタイプ private ItemDataBase.ItemType itemType; // アイテムの情報 private string itemInformation; public ItemData(Sprite image, string itemName, ItemDataBase.ItemType itemType, string information) { this.itemSprite = image; this.itemName = itemName; this.itemType = itemType; this.itemInformation = information; } public Sprite GetItemSprite() { return itemSprite; } public string GetItemName() { return itemName; } public ItemDataBase.ItemType GetItemType() { return itemType; } public string GetItemInformation() { return itemInformation; } } |
アイテム情報にはアイテムの種類を表すアイコン、アイテムの名前、アイテムのタイプ、アイテムの情報を保存出来るようにします。
それぞれのデータを取得できるようにゲッターメソッドを用意します。
他のクラスからItemDataクラスのインスタンスを生成する時に引数に情報を渡し、ItemDataのコンストラクタでデータを設定します。
これでアイテムクラスの作成は終了です。
ItemDataスクリプトはゲームオブジェクトに取り付けません。
次にItemDataBaseスクリプトでアイテムを作成します。
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 ItemDataBase : MonoBehaviour { // アイテムの種類 public enum ItemType { Sword, Gun, Other } // アイテムデータのリスト public List<ItemData> itemDataList = new List<ItemData>(); void Awake() { // アイテムの全情報を作成 itemDataList.Add(new ItemData(Resources.Load("Sword", typeof(Sprite)) as Sprite, "FlashLight", ItemType.Sword, "あれば便利な辺りを照らすライト")); itemDataList.Add(new ItemData(Resources.Load("Sword", typeof(Sprite)) as Sprite, "BroadSword", ItemType.Sword, "普通の剣")); itemDataList.Add(new ItemData(Resources.Load("Gun", typeof(Sprite)) as Sprite, "HandGun", ItemType.Gun, "標準のハンドガン")); } // 全アイテムデータを返す public List<ItemData> GetItemDataList() { return itemDataList; } // 個々のアイテムデータを返す public ItemData GetItemData(string itemName) { foreach (var item in itemDataList) { if(item.GetItemName() == itemName) { return item; } } return null; } } |
ItemDataBaseはゲームに登場するアイテムの情報をすべて保持しておく為のクラスにします。
Awakeメソッドで全てのアイテム情報を設定しています(今回は3アイテムだけです)。
Resources.LoadはAssetsフォルダのResourcesフォルダの中身を取得する時に使います。
Resourcesフォルダは特殊フォルダで、あらかじめResourcesフォルダにインスタンス化したいプレハブ等を入れておくと利用したい時便利です。
第1引数が名前、第2引数が型です。
ItemDataの第2引数はアイテム名、第3引数はアイテムのタイプ、第4引数はアイテムの情報なのでそれぞれのアイテムの情報を書き込みます。
これでItemDataBaseスクリプトの完成です。
シーン全体を通してアクティブであるゲームオブジェクト(例えばMainCamera)にItemDataBaseをAdd Componentで設定しておきます。
持ち物スロット(持ち物アイコンを入れる入れ物)の作成
次に個々のアイテムを入れるスロットを作成します。
Mainの子要素にUI→Panelでパネルを作成し、その子要素にUI→Imageを作成します。
パネルの名前をPropertySlotと変更します。
パネルの大きさはPropertyUIの子要素のMainで設定したGrid Layoutのセルサイズで指定されるので、特別サイズの変更は必要ありません。
作成したPropertySlotはAssetsフォルダにドラッグ&ドロップしてプレハブにし、ヒエラルキー上のPropertySlotは削除します。
持ち物スロットをマウス操作した時の処理スクリプトProcessingSlotを作成
スロットのマウス操作処理関連スクリプトを作成しましょう。
名前はProcessingSlotとし、プレハブのPropertySlotに取り付けます。
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | using UnityEngine; using System.Collections; using UnityEngine.UI; public class ProcessingSlot : MonoBehaviour { // アイテム情報を表示するテキストUI private Text informationText; // アイテムの名前を表示するテキストUIプレハブ [SerializeField] private GameObject itemSlotTitleUI; // アイテム名を表示するテキストUIをインスタンス化した物を入れておく private GameObject itemSlotTitleUIInstance; // 自身のアイテムデータを入れておく public ItemData myItemData; // スロットが非アクティブになったら削除 void OnDisable() { if (itemSlotTitleUIInstance != null) { Destroy(itemSlotTitleUIInstance); } Destroy(gameObject); } // アイテムのデータをセット public void SetItemData(ItemData itemData) { myItemData = itemData; // アイテムのスプライトを設定 transform.GetChild(0).GetComponent<Image>().sprite = myItemData.GetItemSprite(); } void Start() { // アイテムスロットの親の親からInformationゲームオブジェクトを探しTextコンポーネントを取得する informationText = transform.parent.parent.Find("Information").GetChild(0).GetComponent<Text>(); } public void MouseOver() { if (itemSlotTitleUIInstance != null) { Destroy(itemSlotTitleUIInstance); } // アイテムの名前を表示するUIを位置を調整してインスタンス化 itemSlotTitleUIInstance = Instantiate<GameObject>(itemSlotTitleUI, new Vector2(transform.position.x - 25f, transform.position.y + 25f), Quaternion.identity, transform.parent.parent); // アイテム表示Textを取得 var itemSlotTitleText = itemSlotTitleUIInstance.GetComponentInChildren<Text>(); // アイテム表示テキストに自身のアイテムの名前を表示 itemSlotTitleText.text = myItemData.GetItemName(); // 情報表示テキストに自身のアイテムの情報を表示 informationText.text = myItemData.GetItemInformation(); } public void MouseExit() { // マウスポインタがアイテムスロットを出たらアイテム表示UIを削除 if (itemSlotTitleUIInstance != null) { informationText.text = ""; Destroy(itemSlotTitleUIInstance); } } } |
ProcessingSlotはアイテムのスロットに設定し、それぞれのスロットで自身のアイテムデータを保持します。
OnDisableはゲームオブジェクトが非アクティブになった時に呼ばれるので、その時にタイトルUIが存在していればそれを削除し、自身のゲームオブジェクトを削除します。
SetItemDataはこのアイテムスロットを作成した時にそのアイテムのデータを引数として渡し呼び出します。
Startメソッドではアイテム情報を表示するInformationの子要素のTextを取得しています。
MouseOverはアイテムスロットの上にマウスポインタが入った時に呼び出すメソッドで、アイテムの名前を表示するItemSlotTitleUIプレハブをインスタンス化します(ItemSlotTitleUIはこの後作ります)。
itemSlotTitleUIInstanceの位置はスロットのサイズから調整した位置にインスタンス化しています。
アイテムスロットのタイトルUIはPropertyUIの子要素のPanelに設定し、サイズ調整はプレハブで出来るようにします。
アイテムスロットのタイトルUIのテキストには自身のアイテムデータの名前を設定し、Informationのテキストに自身のアイテムの情報を表示します。
MouseExitはマウスポインタがアイテムスロットから出た時の処理で、インスタンス化したitemSlotTitleUIInstanceゲームオブジェクトを削除しています。
これでスロットに関する処理のスクリプトが出来ました。
ItemSlotTitleUIの作成
次はこの処理で使っているItemSlotTitleUIの作成をします。
PropertyUI→Panelの子要素にUI→Panelを作成し名前をItemSlotTitleUIとし、その子要素にUI→Textを作成します。
ItemSlotTitleUIのパネルのサイズは、
↑のように設定します。
その子要素のTextは、
↑のように親のパネルのサイズに合わせて変化させるようにします。
ItemSlotTitleUIもTextもRaycast Targetのチェックを外し、マウスポインタが重なってもイベントを無視するようにします。
ItemSlotTitleUIをAssetsフォルダにドラッグ&ドロップしプレハブ化します。
プレハブ化したら、さきほどのProcessingSlotスクリプトインスペクタのItemSlotTitleUIのところにItemSlotTitleUIのプレハブをドラッグ&ドロップします。
プレハブにしたらヒエラルキー上のItemSlotTitleUIは削除します。
PropertySlotのプレハブを選択し、インスペクタのAdd ComponentからEvent→Event Triggerを取り付けます。
Event TriggerにはPointer EnterとPointer Exitイベントを取り付け、自身のゲームオブジェクト(PropertyUIプレハブ)を設定し取り付けてあるProcessingSlotスクリプトのMouseOverメソッドとMouserExitメソッドを設定します。
イベントトリガーに関しては
を参考にしてください。
これでアイテムスロットの上にマウスが入った時と出て行った時の処理が完成しました。
アイテム数分のスロットを表示するCreateSlotScriptスクリプトを作成する
アイテムの総数分だけスロットを表示し、主人公が持っているアイテムだけスロットを表示するスクリプトを作成します。
名前はCreateSlotScriptとします。
スクリプトはPropertyUI→Panel→Mainに設定します。
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 39 40 41 42 43 44 | using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; public class CreateSlotScript : MonoBehaviour { // アイテム情報のスロットプレハブ [SerializeField] private GameObject slot; // 主人公のステータス [SerializeField] private MyStatus myStatus; // アイテムデータベース [SerializeField] private ItemDataBase itemDataBase; // アクティブになった時 void OnEnable() { // アイテムデータベースに登録されているアイテム用のスロットを全作成 CreateSlot(itemDataBase.GetItemDataList()); } // アイテムスロットの作成 public void CreateSlot(List<ItemData> itemList) { int i = 0; foreach (var item in itemList) { if (myStatus.GetItemFlag(item.GetItemName())) { // スロットのインスタンス化 var instanceSlot = Instantiate<GameObject>(slot, transform); // スロットゲームオブジェクトの名前を設定 instanceSlot.name = "ItemSlot" + i++; // Scaleを設定しないと0になるので設定 instanceSlot.transform.localScale = new Vector3(1f, 1f, 1f); // アイテム情報をスロットのProcessingSlotに設定する instanceSlot.GetComponent<ProcessingSlot>().SetItemData(item); } } } } |
OnEnableメソッドはこのスクリプトを設定しているMainゲームオブジェクトがアクティブになった時に呼ばれるので、その時にCreateSlotメソッドを呼び出します。
CreateSlotメソッドでは受け取ったItemDataの分だけスロットを作成しますが、そのアイテムを持っていなければスロットは作成しません。
なのでMyStatus(主人公キャラのステータス管理スクリプト)でそのアイテムを持っているかを調べます。
持っていたらアイテムスロットプレハブをインスタンス化し、親をMainゲームオブジェクトにします。
その後インスタンス化したアイテムスロットのlocalScaleを全て1に設定します(これをしないと0で初期化され表示されない為)。
最後にインスタンス化したアイテムスロットに設定しているProcessingSlotスクリプトを取得しSetItemDataメソッドを呼び出してアイテム情報をスロットで保持するようにします。
MyStatusスクリプトにアイテムを持っているかどうかの情報保持とアイテムを持っているかどうかを返すメソッドの追記します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // アイテムを持っているかどうかのフラグ private Dictionary<string, bool> itemFlags = new Dictionary<string, bool>(); // アイテムデータベース [SerializeField] private ItemDataBase itemDataBase; private void Start() { // とりあえず全てのアイテムのフラグを作成 foreach (var item in itemDataBase.GetItemDataList()) { itemFlags.Add(item.GetItemName(), false); } // とりあえず適当にアイテムを持っていることにする itemFlags["FlashLight"] = true; itemFlags["BroadSword"] = true; itemFlags["HandGun"] = true; } // アイテムを所持しているかどうか public bool GetItemFlag(string itemName) { return itemFlags[itemName]; } |
主人公のステータススクリプトでアイテムを持っているかどうかを管理します。
Startメソッドでアイテム数分のアイテム名とアイテムを持っているかの情報をDictionaryに保存します。
その後とりあえずゲームスタート時に持っておきたいアイテムのフラグをtrueにしています。
主人公のゲームオブジェクトを選択し、インスペクタのMyStatusでItemDataBaseにItemDataBaseスクリプトを設定したゲームオブジェクトをドラッグ&ドロップします。
これで持ち物画面の作成が完了しました。
持ち物画面を呼び出す処理の追加
持ち物画面が出来たので後はゲームを中断した時に持ち物画面を呼び出し、ゲームを再開した時に消す処理を追加するだけです。
ゲームを中断する方法は
を参考にしてください。
持ち物画面は最初は表示したくないのでPropertyUIゲームオブジェクトは非アクティブにしておきます。
↑のようにPropertyUIを非アクティブにしておかないとエラーが発生します。
これで持ち物画面の作成と呼び出しが出来るようになりました。
回復アイテムを使いたい場合はクリック操作で処理をするという風にするといいかもしれません。
それではUnityの実行ボタンを押して確認してみましょう。
上の画像は動作の一部になります。
画像が少し乱れていますが・・・・。
持ち物画面を作り終えて
とりあえず、これで持ち物画面の作成は終了です。
最初の記事からだいぶ処理を変更しました(2019/06/30)。
以前はだいぶ面倒くさい処理をしてましたが、少しだけスッキリ出来たような気もします。
またいつかこの記事を見た時に修正したくなるかもしれませんが・・・・(^_^;)