HUDメッセージの仕掛けで背景表示しVerseでボタン生成してアイテム選択メニューを作成
OneShotBallistic (島コード: 7218-4337-3934)という島で作ったアイテム選択メニューのverseのコードを記載しておきます。
作ってみたものの、この島からこの機能を削除することにしたので、メモ代わりに残しておきます。
目次
アイテム選択メニューのUIの説明
下記画像は「GET」ボタンを押下すると各アイテムを取得することができるアイテム選択メニューの画面キャプチャです。
このメニューは、アイテムの画像などを配置した背景画像用として作ったBlueprintのUIウィジェットをHUDメッセージの仕掛けで表示しており、「GET」や「CLOSE」というボタンだけはVerseによって生成を行っています。

アイテム選択メニューの背景用の Blueprint UI Widget
フォートナイトの本家バリスティックと同じようなアイテムの並びで、画像や文字、背景を作成しておきます。
各アイテムの右下あたりに Verse で「GET」ボタンを表示するつもりなので、右下は空白になるようにしておきました。

アイテム選択メニューのボタンを生成するVerseのコード
アイテム付与の処理なども別のverseファイルとして作成しているのですが、そういう部分は端折って、ここではボタン生成のverseファイルだけを記載します。
using { /Fortnite.com/Devices}
using { /Verse.org/Simulation}
using { /UnrealEngine.com/Temporary/UI}
using { /Fortnite.com/UI}
using { /UnrealEngine.com/Temporary/SpatialMath}
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Colors }
using { /Verse.org/Assets }
# NOTE: デバッグ用のログ出力のためのもの
log_weapon_select_menu_device := class(log_channel){}
weapon_select_menu_device := class(creative_device):
# NOTE: デバッグ用のログ出力のためのもの
Logger:log = log{Channel:=log_weapon_select_menu_device}
# UI にテキストとして表示するローカライズ可能なメッセージ
TextForMyUI<localizes>(InText:string):message = "{InText}"
# プレイヤーと、そのプレイヤーの UI に追加されている可能性があるウィジェットとの間のマッピング
var MaybeMyUIPerPlayer:[player]?overlay = map{}
# インベントリ制御
# NOTE: 別のverseファイルとして自作したインベントリにアイテム付与する際の処理をまとめたクラス
@editable
InventoryCtrl:inventory_control_device = inventory_control_device{}
# 入力トリガーデバイス
@editable
OpenMenuInputTriggerDevice:input_trigger_device = input_trigger_device{}
# 背景用のHUD
@editable
BackgroundHUDMessageDevice:hud_message_device = hud_message_device{}
# メニューを開くSE
@editable
OpenSEAudioPlayerDevice:audio_player_device = audio_player_device{}
# メニューを閉じるSE
@editable
CloseSEAudioPlayerDevice:audio_player_device = audio_player_device{}
# 武器を選択したSE
@editable
SelectSEAudioPlayerDevice:audio_player_device = audio_player_device{}
# ラウンド開始時
OnBegin<override>()<suspends>:void=
# メニューを開く入力トリガーの押下時のイベントリスナー
OpenMenuInputTriggerDevice.ReleasedEvent.Subscribe(OnOpenWeaponSelectMenuUI)
# ===================================
# 入力トリガー
# ===================================
# 武器選択メニューを開く
OnOpenWeaponSelectMenuUI(Agent:agent, HoldDuration:float):void=
OpenWeaponSelectMenuUI(Agent)
# ===================================
# 武器選択メニューの処理
# ===================================
# 武器選択メニューを開く
OpenWeaponSelectMenuUI(Agent:agent):void=
if (InPlayer := player[Agent], PlayerUI := GetPlayerUI[InPlayer]):
if (MyUI := MaybeMyUIPerPlayer[InPlayer]?):
# NOTE: デバッグ用ログ出力の条件分岐が残ってるだけ。
Logger.Print("OpenUI nope")
else:
# 武器選択メニューの背景画像を表示
BackgroundHUDMessageDevice.Show(Agent)
# 武器選択メニューのUIウィジェットを表示
NewUI := CreateWeaponSelectMenuUI()
# NOTE: InputMode := ui_input_mode.All でキャンバス内の要素をインタラクト可能にする
PlayerUI.AddWidget(NewUI, player_ui_slot{ InputMode := ui_input_mode.All })
if (set MaybeMyUIPerPlayer[InPlayer] = option{NewUI}) {}
# SE再生
OpenSEAudioPlayerDevice.Play(Agent)
# 武器選択メニューを閉じる
CloseWeaponSelectMenuUI(Agent:agent):void=
if (InPlayer := player[Agent], PlayerUI := GetPlayerUI[InPlayer]):
if (MyUI := MaybeMyUIPerPlayer[InPlayer]?):
# 武器選択メニューの背景画像を表示
BackgroundHUDMessageDevice.Hide(Agent)
# 武器選択メニューのUIウィジェットを非表示にする
PlayerUI.RemoveWidget(MyUI)
if (set MaybeMyUIPerPlayer[InPlayer] = false) {}
# SE再生
CloseSEAudioPlayerDevice.Play(Agent)
# ===================================
# 武器選択メニューの中で行う処理
# ===================================
# 武器を付与する
# NOTE: InventoryCtrl は別のverseファイルとして自作したインベントリにアイテム付与する際の処理をまとめたクラス
SelectPistol1(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectPistol1(WidgetMessage.Player) # Hand Cannon
SelectAssaultRifle1(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectAssaultRifle1(WidgetMessage.Player) # Enforcer Assault Rifle
SelectAssaultRifle2(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectAssaultRifle2(WidgetMessage.Player) # Striker Assault Rifle
SelectAssaultRifle3(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectAssaultRifle3(WidgetMessage.Player) # Nemesis Assault Rifle
SelectSMG1(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectSMG1(WidgetMessage.Player) # Thunder Burst SMG
SelectSMG2(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectSMG2(WidgetMessage.Player) # Drum Gun
SelectSMG3(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectSMG3(WidgetMessage.Player) # Hyper SMG
SelectShotgun1(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectShotgun1(WidgetMessage.Player) # Hammer Pump Shotgun
SelectShotgun2(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectShotgun2(WidgetMessage.Player) # Frenzy Auto Shotgun
SelectSniperRifle1(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectSniperRifle1(WidgetMessage.Player) # Reaper Sniper Rifle
# 消耗品を付与する
SelectItemBtn1(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectItem1(WidgetMessage.Player) # Impulse Granade
SelectItemBtn2(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectItem2(WidgetMessage.Player) # Smoke Granade
SelectItemBtn3(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectItem3(WidgetMessage.Player) # Bubble Shield
SelectItemBtn4(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectItem4(WidgetMessage.Player) # Frang Granade
SelectItemBtn5(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectItem5(WidgetMessage.Player) # Flash Bang Granade
SelectItemBtn6(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectItem6(WidgetMessage.Player) # Recon Granade
SelectItemBtn7(WidgetMessage:widget_message):void=
SelectSEAudioPlayerDevice.Play(WidgetMessage.Player) # SE再生
InventoryCtrl.SelectItem7(WidgetMessage.Player) # Proximity Mine
# 武器選択メニューを閉じる
CloseUIinWeaponSelectMenu(WidgetMessage:widget_message):void=
CloseWeaponSelectMenuUI(WidgetMessage.Player)
# ===================================
# UIの生成
# ===================================
CreateWeaponSelectMenuUI():overlay =
# ================= UIウィジェット内に表示するボタン =================
# 武器ボタン
UIPistolBtn1:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIAssaultRifleBtn1:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIAssaultRifleBtn2:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIAssaultRifleBtn3:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UISMGBtn1:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UISMGBtn2:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UISMGBtn3:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIShotgunBtn1:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIShotgunBtn2:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UISniperRifleBtn1:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
# ボタン押下時のイベント登録
UIPistolBtn1.OnClick().Subscribe(SelectPistol1)
UIAssaultRifleBtn1.OnClick().Subscribe(SelectAssaultRifle1)
UIAssaultRifleBtn2.OnClick().Subscribe(SelectAssaultRifle2)
UIAssaultRifleBtn3.OnClick().Subscribe(SelectAssaultRifle3)
UISMGBtn1.OnClick().Subscribe(SelectSMG1)
UISMGBtn2.OnClick().Subscribe(SelectSMG2)
UISMGBtn3.OnClick().Subscribe(SelectSMG3)
UIShotgunBtn1.OnClick().Subscribe(SelectShotgun1)
UIShotgunBtn2.OnClick().Subscribe(SelectShotgun2)
UISniperRifleBtn1.OnClick().Subscribe(SelectSniperRifle1)
# 消耗品ボタン
UIItemBtn1:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIItemBtn2:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIItemBtn3:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIItemBtn4:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIItemBtn5:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIItemBtn6:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIItemBtn7:button_quiet = button_quiet{ DefaultText := TextForMyUI("Get") }
UIItemBtn1.OnClick().Subscribe(SelectItemBtn1)
UIItemBtn2.OnClick().Subscribe(SelectItemBtn2)
UIItemBtn3.OnClick().Subscribe(SelectItemBtn3)
UIItemBtn4.OnClick().Subscribe(SelectItemBtn4)
UIItemBtn5.OnClick().Subscribe(SelectItemBtn5)
UIItemBtn6.OnClick().Subscribe(SelectItemBtn6)
UIItemBtn7.OnClick().Subscribe(SelectItemBtn7)
# 閉じるボタン
UIQuietBtn:button_quiet = button_quiet{ DefaultText := TextForMyUI("Close") }
UIQuietBtn.OnClick().Subscribe(CloseUIinWeaponSelectMenu)
# ================= UIウィジェットを作成 =================
WeaponSelectMenuWidget := overlay:
Slots := array:
# ================= ボタン1列目 =================
# フレンジーオートショットガン
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := -560.0, Top := -313.0 }
Widget := UIShotgunBtn2
# ハンマーポンプショットガン
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := -560.0, Top := -133.0 }
Widget := UIShotgunBtn1
# サンダーバーストサブマシンガン
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := -560.0, Top := 47.0 }
Widget := UISMGBtn1
# ハイパーサブマシンガン
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := -560.0, Top := 227.0 }
Widget := UISMGBtn3
# ドラムガン
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := -560.0, Top := 407.0 }
Widget := UISMGBtn2
# ================= ボタン2列目 =================
# ネメシスアサルトライフル
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := -230.0, Top := -313.0 }
Widget := UIAssaultRifleBtn3
# エンフォーサーアサルトライフル
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := -230.0, Top := -133.0 }
Widget := UIAssaultRifleBtn1
# ストライカーアサルトライフル
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := -230.0, Top := 47.0 }
Widget := UIAssaultRifleBtn2
# ================= ボタン3列目 =================
# ハンドキャノン
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 100.0, Top := -313.0 }
Widget := UIPistolBtn1
# リーパースナイパーライフル
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 100.0, Top := -133.0 }
Widget := UISniperRifleBtn1
# ================= ボタン4列目 =================
# インパルスグレネード
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 430.0, Top := -313.0 }
Widget := UIItemBtn1
# バブルシールド
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 430.0, Top := -133.0 }
Widget := UIItemBtn3
# フラググレネード
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 430.0, Top := 47.0 }
Widget := UIItemBtn4
# リーコングレネード
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 430.0, Top := 227.0 }
Widget := UIItemBtn6
# 地雷
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 430.0, Top := 407.0 }
Widget := UIItemBtn7
# ================= ボタン5列目 =================
# フラッシュバン
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 760.0, Top := -313.0 }
Widget := UIItemBtn5
# スモークグレネード
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Center
Padding := margin{ Left := 760.0, Top := -133.0 }
Widget := UIItemBtn2
# ================= 閉じるボタン最下段 =================
# 閉じるボタン
overlay_slot:
HorizontalAlignment := horizontal_alignment.Center
VerticalAlignment := vertical_alignment.Bottom
Padding := margin{ Bottom := 50.0 }
Widget := UIQuietBtn
return WeaponSelectMenuWidget