Unityを使った3Dゲームの作り方(かめくめ)ゲーム開発エンジンUnityを使った3Dゲームの制作に参考になる情報を公開しています。2019.11.07今回はコマンド画面にアイテムコマンドを追加していきたいと思います。機能が複雑なのと、この記事自体が長いので今回はアイテムコマンドをどうやって実現しようとしているか?とスクリプトの中身を把握しながら作って頂けると助かります。単純に記事も長いのでわかりずらいです。コピペで手っ取り早く機能だけ取り付けるというわけにはいかないのでご了承ください。前回はコマンド画面の作成とステータスコマンドを作成しました。ユニティちゃんのRPGを作ってみよう10ーコマンド画面の作成とステータスの表示ーユニティちゃんのRPGでコマンド画面の作成とステータスコマンドを作成し、選択したキャラクターのステータスを表示するようにしていきます。gametukurikata.com2019.11.06ユニティちゃんのRPGを作ってみようの他の記事はユニティちゃんのRPGを作ってみようユニティちゃんのRPGを徐々に作っていくカテゴリです。gametukurikata.comから見ることが出来ます。前回ステータスコマンドを作成したのと同じようにアイテムコマンドを作成していきます。アイテムコマンドの場合はアイテムコマンドの選択→どのキャラクターの持っているアイテムかの選択→アイテム一覧表示→選択したアイテムの種類に応じて装備や使用等の選択→アイテム使用や渡す場合は使用するキャラクターの選択という流れで条件に応じて新しいパネルをどんどん開く必要があります(昔のドラクエ風)。今回はパネルを複数作成し、状況に応じてどんどん手前に表示する仕様にしたので、そうなりますが画面全体で情報を表示する場所を決めておき、パネルが重ならないようにするという方法もあります。UIの作成は上の流れに沿って作成していく事にします。アイテム一覧は持っているアイテムの種類分のボタンをプレハブからインスタンス化し表示する必要があり、表示領域をスクロールする必要があります。スクロールバーを用意してマウスでスクロールする場合は問題ないですが、PS3コントローラー等のゲームコントローラーでアイテムを選択する場合は自動でアイテムボタン表示領域をスクロール出来ません。スクロールバーにフォーカスを移動出来るようにすれば出来ない事もないですが、これはやめておきます。そこで1回で表示出来るアイテムは何個か決めておいてその表示している最後のボタンの次のボタンを選択したら自動で表示領域がスクロールされるようにします。現時点では何を言ってんの?と思われるかもしれませんが、アイテム一覧の機能を作った時にわかります。アイテムコマンドUIやアイテムコマンドの処理が複雑かつ長くなったのでアイテム一覧のスクロール機能は次回作成していきます。ステータスコマンドの時よりもUIのパネルの数が増えてたり、処理が複雑になっているので注意してください。́Д`)前回のステータスコマンドや今回のアイテムコマンド、このユニティちゃんのRPGを作ってみようのカテゴリ全般でアイテム一覧等はボタンのプレハブをその数分インスタンス化しています。ボタンをヒエラルキー上に配置しておく方法もあります(こちらの方が処理速度が速いかも?)。やり方に関してはこの記事の最後に記載しますが、既にボタンのプレハブをインスタンス化する方法で作ってしまった為、あらかじめボタンを配置して作る方法を個別に詳細に説明はしません。́Д`)アイテムコマンドUIの作成アイテムコマンドで使用するボタンやパネルを作成していきます。アイテムコマンドのパネル構成アイテムコマンドを選択した後のパネルの構成と流れを図にしました。スクリプトで現在どういう状況なのかを保持しておき、それを元に次のパネルを開いたりCancelボタンを押した時に元のパネルに戻ったりを実行します。前のパネルで選択したボタンはselectedGameObjectStackにどんどんプッシュしていき、前のパネルに戻った時にポップして取り出し、前のパネルでどのボタンを選択していたかを把握しそのボタンをフォーカスします。アイテムを選択した状態ではアイテムの使用や渡す、捨てるといったコマンドを表示(UseItemPanel)し、それらを実行した後もそのアイテム数が0より多い場合はそのままUseItemPanelでアイテムをどうするかを選択します。UseItemPanelの捨てるを選択した時やアイテムを使用や渡す相手を選択するUseItemSelectCharacterPanelでキャラクターを選択した後にそのアイテムが0になり、かつそのキャラクターが他のアイテムも一つも持っていない場合はSelectCharacterPanelに処理を移します。そのアイテム自体がなくなっても他のアイテムを持っていればItemPanelに戻ります。アイテムコマンドボタンの作成アイテムコマンドを実行する為のボタンを作成します。Command→CommandPanelの子要素のStatusButtonを選択し、Ctrl+Dキーで複製し名前をItemButtonとします。ClickでCommandScriptのSelectCommandメソッドを呼び出した時の引数はItemに変更します。ItemButtonを押した時はCommandScriptのSelectCommandでアイテムコマンドの処理がされるように後で処理を追加します。ItemButtonの子要素のTextのインスペクタでTextにアイテムと入力します。アイテムを表示するキャラクター選択パネルの作成ItemButtonを押したら次はどのキャラクターのアイテムを表示するかのパネルを表示する必要があります。これはステータスコマンドでどのキャラクターのステータスを表示するか?というSelectCharacterPanelと同じなのでSelectCharacterPanelを使用することにします。アイテム一覧表示パネルの作成どのキャラクターのアイテムを表示するかのボタンを押したら次はそのキャラクターが持つアイテムの一覧とアイテム数等を表示するアイテム一覧パネルを表示する必要があります。Commandゲームオブジェクトを選択した状態で右クリックからUI→Panelを選択しItemPanelという名前にします。ItemPanelのサイズは上のような感じにしました。ItemPanelのImageコンポーネントの横のチェックを外し、表示しないようにします。ItemPanelのインスペクタについては後で変更しますので、その時に画像で設定を紹介します。アイテム一覧のマスク領域の作成ItemPanelを選択した状態で右クリックからUI→Panelを選択し、名前をMaskとします。ComponentからUI→Maskを選択し取り付けます。このMaskゲームオブジェクトはMaskコンポーネントを取り付けているので子要素のアイテムボタンやテキスト等が範囲外(Mask領域外)に出た時は表示されなくなります。アイテムパネルボタンを表示する領域の作成Maskを選択した状態で右クリックからUI→Panelを選択し、名前をContentとします。stretchにし開始位置はMaskの上、横幅はMaskの幅にし、Heightを3000としておきます。Heightの値はアイテム一覧全体の長さになるので、アイテムを表示する数に応じて数値をより大きくする必要があります。Groupを取り付け以下のように設定します。Groupはグリッドで子要素のコンテンツを整列させることが出来ます。Countに設定し、Countを2にして横に2個アイテムボタンを表示したら下に表示するようにします。個々のアイテムを表すItemPanelButtonプレハブの作成Contentの子要素に配置する個々のアイテムを表すItemPanelButtonプレハブを作成していきます。Contentを選択した状態で右クリックからUI→Buttonを選択し、名前をItemPanelButtonとします。Imageのチェックを外し、ButtonのTransitionをNoneにします。Clipに設定します。Centerにします。新しくItemPanelButtonScriptスクリプトを作成し取り付けます。Groupコンポーネントを取り付けたので子要素のUIの要素が横に整列します。ItemPanelButtonScriptは以下のように作成します。item;}}SetParamメソッドはCommandScriptメソッドから呼び出してアイテムボタン個々でアイテム情報を保持し、アイテムパネルボタンが選択されたらアイテム情報を表示します。ItemPanelButtonの子要素にUIのImageとTextを4つ作成し、Textの名前をEquip、ItemName、Multiply、Numと変更します。Sizeは25にします。Imageはボタンを選択した時のアイコンの設定でStatusButtonやItemButtonと同じです。Equipは装備している武器や鎧である場合にEを表示するのに使い、ItemNameはアイテム名、Multiplyはアイテムの個数を表す×を表示し、Numにはアイテムの個数を表示します。Equip、MultiplyのAlignmentは中央にし、ItemNameは左揃え、Numは右揃えにしておきます。Groupでセルのサイズを指定しているので、Widthを300、Heightを50にし、子要素のImageやテキスト群はそれに合わせてWidthとHeightを調整したり位置を調整してください。わたくしの場合はImageのWidthとHeightを30にし、それ以外のText群のHeightは50に固定で、EquipのWidthは30、ItemNameのWidthは140、MultiplyのWidthは20、NumのWidthは50にしてみました。配置としては以下のようになります。EquipのTextコンポーネントのTextは空にしておきます。ここまで出来たらItemPanelButtonをAssets/RPG/Prefabs/UI/Commandフォルダ内にドラッグ&ドロップしてプレハブにします。ヒエラルキー上のItemPanelButtonはこの後使いますので残しておきます。アイテムパネルボタンをとりあえず並べてみるアイテムパネルボタンがどのように表示されるかを確認する為に、ヒエラルキー上のItemPanelButtonをCtrl+Dキーで複製し20個に増やしてみます。するとシーンビューでは以下のように表示されます。アイテムが表示されるのはMaskパネルの領域だけなのでアイテムボタンが16個までしか表示されず、その下のアイテムボタンは見えません(ItemPanelのサイズによって数は変わります)。表示されている15個目と16個目のアイテムボタンは少し切れています。そこでMaskパネルの領域を少し狭めてアイテムが14個まで完全に表示される状態にします。これでとりあえず1回に見える範囲は14個のアイテムだけになりました。RectコンポーネントとScrollbarが必要になります。Groupを取り付けます。ItemPanelを選択した状態で右クリックからUI→Scrollbarを選択します。rightにしWidthを20、Heightを160とします(WidthとHeightは任意です)。TopにしValueを1とします。Rectコンポーネントの設定をします。TypeをClampedにします。ClampedにするとContentゲームオブジェクトの子要素のアイテムボタンの表示領域で制限されて動きます。マウスでスクロールする場合はContentの領域内で動きます。Scrollbarに先ほど作ったScrollbarゲームオブジェクトを設定します。Groupのinteractableのチェックを外していますが、これはスクリプトから有効と無効を切り替えるので最初は無効としておく必要があります。今はマウスでスクロールするのを確認したいのでinteractableにチェックを入れます。これでContent領域をマウスでドラッグしたり、スクロールバーをドラッグすることでアイテム一覧の領域を移動出来るようになりました。ゲームコントローラーでアイテムを選択して下に移動していってもアイテム一覧はスクロールしてくれません。ゲームコントローラーでアイテム一覧をスクロールするやり方は次回作成するので、UIの続きを作成していきましょう。ItemPanel子要素のContent以下に作成したItemPanelButton達は全て削除し、Content以下には何もゲームオブジェクトがないようにします。Groupのinteractableのチェックを外しておきます。アイテムを選択した時に表示するパネルの作成アイテム一覧パネルでアイテムボタンを押した時に表示するパネルを作成します。Commandを選択した状態で右クリック→Panelを選択し、名前をUseItemPanelとします。表示領域は以下のようにしました。Layoutを取り付けます。設定については今まで作成してきたパネルと同じです。次にUseItemPanelの子要素にAssets/RPG/Prefabs/UI/Command/CharacterButtonをドラッグ&ドロップします。Completelyを選択しプレハブとのリンクを解除し普通のゲームオブジェクトにします。したら名前をUseItemButtonとし、Assets/RPG/Prefabs/UI/Commandフォルダにドラッグ&ドロップしてプレハブにします。プレハブにしたらヒエラルキー上のUseItemButtonは削除します。次にアイテムを選択した時に表示したパネル(UseItemPanel)で『使う』や『渡す』を選択した時に表示する誰にアイテムを使うのか?を表示するパネルを作成します。UseItemPanelゲームオブジェクトを選択しCtrl+Dキーで複製し、名前をUseItemSelectCharacterPanelとします。UseItemSelectCharacterPanelの領域は以下のようにしました。UseItemSelectCharacterPanelに表示するボタンはSelectCharacterPanelと同じCharacterButtonなので特に作成しません。アイテム情報の情報を表示するパネルの作成アイテム情報を表示するパネルを作成していきます。Commandを選択した状態で右クリックからUI→Panelを選択し、名前をItemInformationPanelとします。ItemInformationPanelの子要素にUI→Textを二つ作成し、名前をTitleとInformationにし、以下のような領域にします。Titleにはアイテムのタイトル、Informationにはアイテム情報やアイテムを使用した時の情報を表示します。Sizeは25にしました。アイテムの装備や使用等をした時の情報表示パネルの作成アイテムの装備や使用等をした時にもItemInformationPanelのInformationのテキストに表示しようと思ったんですが、ItemPanelButtonScriptでボタンが選択された時にアイテム情報を更新しているので、これがうまく出来ません。そこでアイテムを装備や使用した時は別のパネルを作りそこに情報を表示しようと思います。Commandを選択した状態で右クリックからUI→Panelを選択しUseItemInformationPanelとし子要素にUI→Textを作成します。stretchにしUseItemInformationPanelの大きさに応じてTextの幅も変えます。Sizeは30にしました。Centerにします。UseItemInformationPanelは以下のような位置とサイズにしました。これでアイテムコマンドに関するUIの作成が完了しました。CommandScriptにアイテムコマンドの処理を追加するUIが出来たので後はItemButtonを押した後のアイテムコマンドの処理をCommandScriptに追加していくだけです。追加していくだけですと言うと簡単なように思えますが、処理は面倒な事をしています。(^_^;)CommandModeにモードを追加するまずはCommandModeにモードを追加します。{CommandPanel,StatusPanelSelectCharacter,StatusPanel,ItemPanelSelectCharacter,ItemPanel,UseItemPanel,UseItemSelectCharacterPanel,UseItemPanelToItemPanel,UseItemPanelToUseItemPanel,UseItemSelectCharacterPanelToUseItemPanel,NoItemPassed}持っているアイテムを表示するキャラクターのパネルを開いた状態(ItemPanelSelectCharacter)アイテム一覧のパネルの状態(ItemPanel)アイテムの使用や渡す、捨てる等を表示するパネルの状態(UseItemPanel)使用するアイテムを使うキャラクター選択のパネルの状態(UseItemSelectCharacterPanel)アイテム装備、装備を外すをした後の状態(UseItemPanelToItemPanel)アイテムを捨てるを選択した後にまだそのアイテムがある状態(UseItemPanelToUseItemPanel)アイテムを使用、渡すを選択した後に使用する、渡す相手を選択した後の状態(UseItemSelectCharacterPanelToUseItemPanel)アイテムを使用、渡す、捨てるを選択した後にそのアイテムが0になり他のアイテムも一つも持っていない状態(NoItemPassed)になります。フィールド宣言フィールドを追加します。List<GameObject>();作成したパネルのフィールドやテキスト、アイテムボタンや使用するアイテムのボタンのプレハブを作りプレハブにはインスペクタで設定する必要があります。itemPanelButtonListにはアイテム一覧に表示したボタンのゲームオブジェクトを登録しておき、武器を装備した時や外した時にアイテムの名前の前のEquipを表すEの文字を表示したり消したりする時に使用します。Awakeメソッドに処理を追加Awakeメソッドにフィールドに設定するゲームオブジェクト等の取得をする処理を追加します。itemInformationPanel.transform.Find("Information").GetComponent<Text>();行っていることは階層を辿って該当するゲームオブジェクト、CanvasGroup、Textを取得しているだけです。OnEnableメソッドに処理を追加OnEnableメソッドにパネルの非表示等の処理を追加します。false;Commandがアクティブになった時に以前作成したボタンの削除、リストのクリア、CanvasGroupの初期化を行っています。Updateメソッドに処理を追加するUpdateメソッドに処理を追加していきます。Cancelボタンを押した時の処理UpdateメソッドでCancelボタンが押された時に現在どのコマンドモードかを調べ処理を分岐させている所に新しく追加した状態の条件を加えます。CommandMode.UseItemPanel;}やっていることは同じなので割愛します。ほとんど同じ処理をしているのでメソッドに切り分けることも出来そうです。ややこしくなるので同じような記述をズラズラと書いています。アイテム使用後の情報を消し次の事を行う為の処理アイテムを装備、装備を外す、使用、渡す、捨てるといった事を行ったらUseItemInformationPanelの子要素のTextに何をしたか?の情報を載せます。その情報を載せた状態で何らかのキーを押した時に次の動作に移行させる為の処理を記述します。true;selectCharacterPanel.SetActive(true);EventSystem.current.SetSelectedGameObject(selectedGameObjectStack.Pop());}}}アイテムをどうするか?をUseItemPanelで選択した後にどうしたのか?の情報をUseItemInformationPanelに表示していますが、その後に何らかのキーを押したらUseItemInformationPanelを非表示にしてから次の行動が出来るようにしています。currendCommandの状態に応じてキーが押されたらどのパネルのCanvasGroupのinteractableを操作して、どのパネルをアクティブにするか等の処理をしています。Buttonであるボタンが押された時、キーボードのキーを押した時マウスボタンを押した時等にtrueになります。Axisの場合は反応しません。0f)等の条件を加えて、十字キーやジョイスティックが少しでも押されていたら条件が成立するようにしています。SelectCommandメソッドに処理を追加するSelectCommandにItemButtonを押した時に処理をする部分を追加します。SelectCommandはCommandPanelのボタンが押された時の処理をしていました。送られてきた文字列がStatusの時のif分の下にItemの時の処理を追加します。CreateItemPanelButton(member));}}行っていることはStatusの時とほとんど同じで作成したボタンが押された時にCreateItemPanelButtonメソッドを呼び出すだけです。AddListenerの引数にはラムダ式を指定し、ボタンがクリックされたら無条件にCreateItemPanelButtonメソッドに引数memberを渡して呼び出します。ラムダ式についてはC#でデリゲートとラムダ式を使ってみるC#のデリゲートとラムダ式をUnity付属のMonoDevelopで使用してみます。gametukurikata.com2017.10.16を参照してください。CreateItemPanelButtonメソッドの作成CreateItemPanelButtonメソッドはどのキャラクターのアイテムを表示するかのボタンを押した時に実行されるメソッドです。どのキャラクターのアイテムを表示するかの選択がされた後の処理なのでItemPanelを表示し、そこに個々のアイテムを表すItemPanelButtonプレハブからインスタンスを生成していきます。"アイテムを持っていません。"アイテムを持っていません。true;}}アイテム一覧を表示するのでitemInformationPanelを表示し、アイテムを選択した時にそのアイテムの情報を見れるようにします。前のパネルのCanvasGroupであるselectCharacterPanelCanvasGroupはfalseにしSelectCharacterPanelのボタンは選択出来ないようにします。allyStatus.GetItemDictionary().Keysでそのキャラクターが持っているアイテムのキーが全て取得出来るのでforeachを使って全部のアイテムのボタンを作成していきます。ItemPanelButtonPrefabはItemPanelの子要素のContentゲームオブジェクトの子要素としてインスタンス化します。インスタンス化したボタンの子要素からItemNameという名前のゲームオブジェクトのTextコンポーネントを取得し、item.GetKanjiName()でアイテムの漢字名を取得し入れています。item));の処理です。今プレハブからインスタンス化したItemPanelButtonPrefabのButtonコンポーネントを取得しonClick(ボタンを押した時)にAddListenerメソッドを使って実行するメソッドを登録しています。アイテムパネルボタンを押した時はSelectItemメソッドに引数allyStatus(そのキャラクターのステータス)とitem(このボタンを表しているアイテム)を渡します。ItemPanelButtonPrefabにはあらかじめItemPanelButtonScriptを取り付けてあるのでSetParamメソッドを使ってItemを渡しています。アイテムパネルボタンにはアイテムの数とそのアイテムが装備している武器や鎧だった時はEを表示する箇所があるので、情報を取得してそれを設定しています。アイテムパネルボタンのインスタンスが出来たらitemPanelButtonListに登録しておきます。アイテム一覧にアイテム数分のアイテムパネルボタンが出来たらContentの最初の子要素を選択している状態にします。キャラクターがアイテムをひとつも持っていなければ情報を表示し、SelectCharacterPanelに戻ります。次にアイテム一覧に表示した個々のアイテムボタンを押された時に実行するSelectItemメソッドを作成していきます。SelectItemメソッドではそのアイテムに対してどういった操作が可能かを判断しUseItemPanelに対応するボタンを作成します。true;Input.ResetInputAxes();}}アイテムの種類に応じて選択出来る項目のタイトルやボタンを押された時に実行するメソッドの設定を変えています。アイテムが装備品の場合で既に装備している装備品であれば『装備を外す』(RemoveEquipメソッド)、装備していなければ『装備する』(Equipメソッド)、『渡す』(PassItemメソッド)『捨てる』(ThrowAwayItemメソッド)をぞれぞれ実行します。回復アイテム(Item.Type.HPRecovery、Item.Type.MPRecovery)、状態回復アイテム(Item.Type.NumbnessRecovery、Item.Type.PoisonRecovery)の場合は『使う』(UseItemメソッド)、『渡す』『捨てる』ボタンを表示します。貴重品(Item.Type.Valuables)の場合は情報表示パネルにアイテム情報を表示するだけです。貴重品以外のアイテムであればcurrentCommandを変更し、現在選択しているボタンをselectedGameObjectStackにプッシュし、UseItemPanelの最初のボタンを選択状態にします。Input.ResetInputAxes()メソッドはそのフレームでの入力をリセットし同じフレーム内で連続してキーやボタンが押されたと判断されない為に入れています。選択したアイテムをどうするか?の『使う』ボタンを押した時に実行するUseItemメソッドを作成していきます。true;Input.ResetInputAxes();}選択したアイテムを『使う』という選択をしたので、現在選択している『使う』ボタンをselectedGameObjectStackにプッシュし、UseItemSelectCharacterPanelにパーティーメンバー分のボタンをプレハブからインスタンス化し、そのボタンが押された時にUseItemToCharacterメソッドが実行されるようにします。アイテムを使う事にしたので誰に使うか?のボタンを表示するUseItemSelectCharacterPanelの子要素に表示するボタンの作成とそのボタンを押した時に実行するメソッドを指定しています。UseItemToCharacterメソッドの作成アイテムを使うキャラクターを選択した時に実行するUseItemToCharacterメソッドを作成します。