Unityでキャラクターの持ち物画面を作成する

今回はUnityで持ち物の画面を作成したいと思います。
ゲーム中にPauseモードでPauseUIを表示する代わりにステータス画面や持ち物画面を表示します。

今回は持ち物画面を表示するようにします。
全部の持ち物分のスロット(入れ物)を用意して、持っているアイテムは種類を表すアイコンをスロットに表示します。
スロットをクリックしたら情報欄にそのアイテムの情報を表示します。

今回作成する持ち物画面はマウス操作で実行しますので、ゲームパッドやキー操作出来る持ち物画面を作りたい方は

Unityでキーやゲームパッドで操作するステータス画面の作成
UnityのゲームでPS3コントローラー(ゲームパッド)で操作出来るステータス画面を作成していきます。

を参照してください。

スポンサーリンク

持ち物画面UIを作成

まずはPropertyUIという名前でUIを作成していきます。

プロパティ1

CanvasをPropertyUIという名前に変更し、子要素にPanel、その子要素にPanelを3つ作成し、Title、Main、Informationと作成します。
Informationには子要素にUIのTextを作成します。

プロパティ2

上のようにTitle、Main、Information(色ごとに分けてあります)という順になるように作成します。
名前やレイアウトは自由に変更してください。

プロパティ3

Mainのインスペクタを表示し、Add ComponentからLayout→Grid Layoutを選択します。
Cell Sizeで横幅と縦幅を指定します。Spacingでセル間の距離を指定します。

Start Cornerはどこから最初のセルを表示するか
Start Axisは縦と横のどちらにセルを並べていくか
Child Alignmentは子要素の並び位置
Constraintsは行と列の数に制限を持たせる

という設定になります。

今回は上の画像のように設定しました。

アイテムクラスItemDataとアイテム情報管理スクリプトItemDatabaseを作成

次にアイテムの情報を管理する為に、ItemDataクラススクリプトとアイテムの情報を保存しておくItemDatabaseスクリプトを作成します。
Javascriptでプログラミングしてきてクラスという概念は意識していませんでしたが、アイテムの情報をひとまとめに扱えると便利なので今回はJavascriptでクラスを使います。

ItemDataというスクリプトを作成します。

アイテム情報にはアイテムの種類を表すアイコン、アイテムの名前、アイテムの情報を保存出来るようにします。
classでスクリプト名と同じ名前でクラス宣言をし、中身にfunctionでスクリプトと同じ名前の関数を作成します。
これがコンストラクタ(クラスを実体化する時に呼ばれる)でクラスからインスタンス化する時にデータを初期化する時に便利です。

それぞれのデータを取得できるようにゲッター関数を用意します。
これでアイテムクラスの作成は終了です。

次にItemDatabaseスクリプトでアイテムを作成します。

Start関数内でItemDataクラスをインスタンス化しItemData型の配列変数に入れます。

Resources.LoadはAssetsエリアのResourcesフォルダの中身を取得する時に使います。
あらかじめResourcesフォルダにインスタンス化したいプレハブ等を入れておくと利用したい時便利です。

第1引数が名前、第2引数が型です。
ItemDataの第2引数はアイテム名、第3引数はアイテムの情報なのでそれぞれのアイテムの情報を書き込みます。

これでItemDatabaseスクリプトの完成です。
シーン全体を管理するスクリプトにItemDatabaseをAdd Componentで設定しておきます。
過去記事の内容を作って頂いている方はScriptオブジェクトに設定してください。

持ち物スロット(持ち物アイコンを入れる入れ物)の作成

次に持ち物を入れるスロットの作成をします。

プロパティ4

シーン上にUI→Panelでパネルを作成し、その子要素にUI→Imageを作成します。
パネルの名前をPropertySlotと変更します。

パネルの大きさはPropertyUIの子要素のMainで設定したGrid Layoutのセルサイズで指定されるので、特別サイズの変更は必要ありません。

というか、Canvasの子要素にしていないので、サイズの変更は出来なさそうです。

スロット番号記憶スクリプトSlotNumを作成

PropertySlotはマウスポインタが上に来たらアイテムの名前を表示するのと、マウスを外れたらアイテムの名前を消し、
クリックされたらInformationのテキストにアイテムの情報を表示するようなスクリプトを設定します。

アイテムの情報を表示する為に、そのスロットがどのアイテムと対応しているかの情報が必要になります。
そこでスロット毎に番号を割り振り、その番号を元にアイテムの情報を取得するようにします。

PropertySlotにSlotNumというスクリプトを作り取りつけます。

このスクリプトはスロットの番号を保持するだけのスクリプトです。

持ち物スロットをマウス操作した時の処理スクリプトProcessSlotを作成

ではスロットのマウス操作処理関連スクリプトを作成しましょう。
名前はProcessSlotとします。

Start関数内でItemDatabaseスクリプトの取得、自分自身に設定されているSlotNumスクリプトの取得、Informationに設定されているテキストの取得、プレイヤーのステータス管理スクリプトMyStatusの取得を行います。

プレイヤーのステータスはアイテムを持っているかどうかという情報を得る為に取得しています。

次にクリックした時に実行する関数OnClickを見ていきます。

OnClickは独自関数なので名前は自由に変更してください。
status.GetItemFlag(slotNum.GetSlotNum())で主人公がスロットと対応するアイテムを保持しているか確認します。
スロット番号とアイテム番号は対応させて管理するのでこういう事が出来ます。

アイテムを持っていたら、そのアイテムの情報をItemDatabaseから取得しItemData型のitem変数に保持します。

アイテムの名前を赤色にして改行、その後、アイテム情報を足したテキストをInformationのテキストに表示します。
アイテムを持っていないスロットがクリックされた時はInformationテキストを空文字にしています。

次はマウスがスロットの上にいる時の処理MouseOverです(これも独自関数)
アイテムを持っていて、uiObj(アイテムのタイトルのUI)が表示されていない時
uiObjにtitleUIで指定したゲームオブジェクトを表示します。

表示する位置はProcessSlotが設定されているオブジェクトの位置から少し調整した位置になります。
uiObjを置く位置は

uiObj.transform.SetParent(transform)

とします。
transform.SetParentでこのオブジェクトの親を指定出来ます。タイトルUIはスロットの子要素にしたいので、親をtransform(ProcessSlotスクリプトが設定されているゲームオブジェクトPropertySlot)とします。

アイテムデータをデータベースから取得し、アイテムの名前をタイトルUIのテキストに表示します。

次にスロットからマウスが離れた時の処理MouseExit(これも独自関数)です。
マウスがスロットから離れた時にする事は、タイトルUIが表示されていた時はInformationのTextに空文字を入れるのと、タイトルUIを削除する事です。

これでスロットに関する処理のスクリプトが出来ました。

TitleUIの作成

次はこの処理で使っているTitleUIの作成をします。

シーン上にUIのCanvasを作り、その子要素にUIのPanel、その子要素にUIのTextを作成します。
Canvasの名前をItemTitleUI、TextをTitleと変更します。

プロパティ5

プロパティ6

ItemTitleUIのインスペクタでRender ModeをWorld Spaceと変更し、CanvasのサイズでWidthを70、Heightを25とします。
子要素のTitleもWidthを70、Heightを25とします。

Assetsエリアにドラッグ&ドロップしプレハブ化します。
プレハブ化したら、さきほどのProcessSlotのtitleUIのところにItemTitleUIのプレハブをドラッグ&ドロップします。

プロパティ7

次にPropertySlotにAdd ComponentからEvent→Event Triggerを追加します。
このPropertySlotで何らかのイベントが発生したらProcessSlotスクリプトのそれぞれの関数を呼び出すという感じになります。
上の画像のようにイベントトリガーを設定しました。

イベントトリガーに関しては

UnityのUIのクリックやドラッグのイベントを受け取る
UnityのUIのクリックやドラッグのイベントをEvent Triggerコンポーネントを取りつけて受け取れるようにします

を参考にしてください。

これでスロットがマウスクリックされた時の処理等が完成しました。

アイテム数分のスロットを表示するSetSlotItemスクリプトを作成する

それではアイテムの総数分だけスロットを表示し、主人公が持っているアイテムだけスロットにアイコンを表示するスクリプトを作成します。
名前はSetSlotItemとします。
スクリプトはPropertyUIのMainに設定します。

Start関数内で主人公のステータス、アイテムデータベースの取得、スロットのゲームオブジェクトをデータベースの数分確保します。

SetItemToSlot関数でデータベースの総数分のスロットをインスタンス化、名前の設定、親をSetSlotItemが設定されているゲームオブジェクト(Main)にし、そのアイテムを持っていたらスロットの子要素のImageを取得しspriteを設定します。
spriteは2Dの画像です。

アイテムを持っていなかったらImage自体を非表示にします。

スロットに設定されているSlotNumを取得しスロット番号にiの値を設定します。
ここでのiの値がデータベースの番号、スロットの番号と対応しています。

DeleteSlot関数ではステータス画面が非表示される時に呼び、作成したスロットを全部削除します。
ステータス画面を開く時はSetItemToSlot関数が呼ばれ、アイテムのスロットとアイテムの保持情報を更新するようにします。

SetSlotItemスクリプトの作成が終了したのでインスペクタでslotにPropertySlotを設定します。

さて、これで持ち物画面の作成が完了しました。

持ち物画面を呼び出す処理の追加

後はゲームを中断した時に持ち物画面を呼び出し、ゲームを再開した時に消す処理を追加するだけです。
ゲームを中断する方法は

Unityでゲームの中断が出来るようにする
Unityのゲームで一時中断してポーズの表示をする機能を作成していきます。

を参考にしてください。

ゲーム中断スクリプトが書いてあるスクリプトManagementスクリプトを修正します。

public var ui : GameObject;

uiというpublic変数を宣言し、インスペクタでPropertyUIをドラッグ&ドロップします。
Start関数で

ui.SetActive(false);

とします。持ち物画面は最初は表示したくないので非アクティブにしておきます。

ゲーム中断する時は上のようにUIをアクティブにし、SetSlotItemを子要素から取得し、SetItemToSlot関数を呼び出して、アイテムスロットの設定とアイテムの設定をします。

ゲームを中断から再開させる時は持ち物画面であるUIを非アクティブにし、DeleteSlot関数を呼んでスロットの削除をしておきます。

これで持ち物画面の作成と呼び出しが出来るようになりました。

今回はアイテムスロットをクリックしたらInformationのTextにアイテム情報を表示していますが、クリックしないで、マウスがアイテムスロットの上にきたら情報を表示したい場合、OnClick関数内の処理をMouseOver関数内に記述します。

そうすることでマウスの移動のみで情報の表示が出来るようになります。

回復アイテムを使いたい場合はクリック操作で処理をするという風にした方がいいかもしれません。
クリックで情報を表示するという仕様でやってきてしまったので、記事内では面倒臭い仕様になってますが・・・。

それではUnityの実行ボタンを押して確認してみましょう。

プロパティ8

上の画像は動作の一部になります。
画像が乱れているのはわたくしのパソコンが古い為か、Direct3D11を使うとテキスト関連が乱れます。

UnityのEditメニュー→Project Settings→Player→Other SettingsのAuto Graphics APIのチェックを外し、Direct3D11を削除しようと思いましたが、削除中にメモリ不足で落ちる為どうしようもありませんでした・・・。
消す必要がなくDirect3D9を上に移動すればよさそうです。

が!そうしても画面の乱れは解消されませんでした・・・。

持ち物画面を作り終えて

とりあえず、これで持ち物画面の作成は終了です。

PropertyUIをプレハブ化してゲームの中断ごとにインスタンスを作成しようと思いましたが、
スロットは作成されるもののスロット自体が見えないという事態に陥り、原因不明のまま解決出来なかった為、仕様を変更しました。

武器の切り替え等でアイテムの位置を変更する場合はアイテムのドラッグ&ドロップでアイテムの位置交換が出来ると便利ですが、
今回は持ち物の情報を得るだけの機能です。

今回の仕様ではスロット番号とアイテム番号が一致している必要があり、アイテムの交換には対応していません。
装備を変更する機能は

持ち物画面で装備スロットに装備品を入れる機能をUnityで作る
Unityの持ち物画面で装備スロットにマウスのドラッグ&ドロップで武器を設定出来るようにします

を参照してください。