🧑‍🎨

[UEFN]VerseでUIを作成して表示する方法

2024/02/09に公開

仕組み

PlayerにUIが紐づいていて、UIのWidgetにCanvasを設置できる
CanvasにはWidgetを複数設定できる
構造的には下記のイメージ

Player
└PlayerUI
 └Canvas Widget
  └Widget(ButtonやImageなどをSlotで割り当て)

実装方法

PlayerからUIを取得して、取得したPlayerUIにWidgetを設定したCanvasを割り当てる。

CanvasのスロットにWidgetを配置し、PlayerにAdd
例えば、
Overlay TyepeのWidgetを表示したければ、CanvasのSlotのWidgetプロパティに設定して
そのCanvasをユーザーに割り当てる。
配置場所は、各SlotのAnchors, Alignment, Offsets, SizeToContentで設定

CanvasにCanvasを割り当てることもできます

参考ドキュメント:

・Widgetの種類
https://dev.epicgames.com/documentation/en-us/uefn/widget-types-in-unreal-editor-for-fortnite

・割り当て方の公式docs
https://dev.epicgames.com/documentation/en-us/uefn/positioning-widgets-on-the-screen-in-unreal-editor-for-fortnite

・Colors
https://dev.epicgames.com/documentation/it-it/uefn/verse-api/versedotorg/colors/namedcolors

各色のイメージ
https://www.w3schools.com/cssref/css_colors.php

MyButtonは別途レベル上のオブジェクトと紐づける必要あり

紐づけ方:
カスタム型をエディタに公開する
https://dev.epicgames.com/documentation/ja-jp/uefn/customize-verse-device-properties-in-verse

Verseファイルの作成やビルドは下記参照:
https://dev.epicgames.com/documentation/ja-jp/uefn/create-your-own-device-in-verse

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/SpatialMath}
using { /Verse.org/Colors }

custom_ui_canvas := class(creative_device):

    # ボタンの仕掛けをエディタ内で設定して、レベル内でその仕掛けを参照するようにします
    @editable
    MyButton : button_device = button_device{}

    # UI にテキストとして表示するローカライズ可能なメッセージ
    TextForMyUI<localizes>(InText : string) : message = "{InText}"

    # プレイヤーと、そのプレイヤーの UI に追加されている可能性があるウィジェットとの間のマッピング
    # キーがplayerでvalueがcanvas
    var MaybeMyUIPerPlayer : [player]?canvas = map{}

    # 実行中のゲームで仕掛けが開始されたときに実行します
    OnBegin<override>()<suspends> : void =
        MyButton.InteractedWithEvent.Subscribe(HandleButtonInteraction)

    # カスタム仕様の UI は特定のプレイヤーのみに関連付けることができ、そのプレイヤーのみが表示できます
    HandleButtonInteraction(Agent : agent) : void =
        # エージェントはプレイヤーか AI にすることができますが、取得できるのはプレイヤーの UI のみであるため、
        # プレイヤー タイプには、ボタンの仕掛けとやり取りしたエージェントをキャストする必要があります
        if (InPlayer := player[Agent], PlayerUI := GetPlayerUI[InPlayer]):
            
            # プレーヤーにウィジェットが表示されているかどうかを確認
            if (MyUI := MaybeMyUIPerPlayer[InPlayer]?):
                PlayerUI.RemoveWidget(MyUI)
                if (set MaybeMyUIPerPlayer[InPlayer] = false) {}
            else:
                NewUI := CreateMyUI()
                PlayerUI.AddWidget(NewUI)
                if (set MaybeMyUIPerPlayer[InPlayer] = option{NewUI}) {}
    
    # テキスト付きのボタンを画面のさまざまな位置に表示するキャンバス ウィジェット
    CreateMyUI() : canvas =
        MyCanvas : canvas = canvas:
            Slots := array:
                canvas_slot: # 画面左上, Button
                    Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.0}, Maximum := vector2{X := 0.0, Y := 0.0}}
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 0.0, Y := 0.0}
                    SizeToContent := true
                    Widget := button_loud{DefaultText := TextForMyUI("Upper Left")}
                canvas_slot: # 画面中央上, Button
                    Anchors := anchors{Minimum := vector2{X := 0.5, Y := 0.0}, Maximum := vector2{X := 0.5, Y := 0.0} }
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 0.5, Y := 0.0}
                    SizeToContent := true
                    Widget := button_loud{DefaultText := TextForMyUI("Upper Middle")}
                canvas_slot: # 画面右上, Button
                    Anchors := anchors{Minimum := vector2{X := 1.0, Y := 0.0}, Maximum := vector2{X := 1.0, Y := 0.0}}
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 1.0, Y := 0.0}
                    SizeToContent := true
                    Widget := button_loud{ DefaultText := TextForMyUI("Upper Right")}
                canvas_slot: # 画面左中央, Button
                    Anchors := anchors{ Minimum := vector2{X := 0.0, Y := 0.5}, Maximum := vector2{X := 0.0, Y := 0.5}}
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 0.0, Y := 0.5}
                    SizeToContent := true
                    Widget := button_loud{DefaultText := TextForMyUI("Middle Left")}
                canvas_slot: # 画面中央, Button
                    Anchors := anchors{Minimum := vector2{X := 0.5, Y := 0.5}, Maximum := vector2{X := 0.5, Y := 0.5}}
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 0.5, Y := 0.5}
                    SizeToContent := true
                    Widget := button_loud{DefaultText := TextForMyUI("Center")}
                canvas_slot: # 画面右中央, CanvasにCanvasを配置
                    Anchors := anchors{Minimum := vector2{X := 1.0, Y := 0.5}, Maximum := vector2{X := 1.0, Y := 0.5}}
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 1.0, Y := 0.5}
                    SizeToContent := true
                                        Widget := canvas:
                        Slots := array:
                            canvas_slot: # 画面左上
                                Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.0}, Maximum := vector2{X := 0.0, Y := 0.0}}
                                Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                                Alignment := vector2{X := 0.0, Y := 0.0}
                                SizeToContent := true
                                Widget := overlay:
                                    Slots := array:
                                        overlay_slot:
                                            Widget := color_block:
                                                DefaultColor := NamedColors.AliceBlue
                                                DefaultOpacity := 1.0
                                                DefaultDesiredSize := vector2{X := 1024.0, Y := 128.0}                                
                                        overlay_slot:
                                            Widget := text_block:
                                                DefaultText := TextForMyUI("俊足")
                canvas_slot: # 画面左下, Slider
                    Anchors := anchors{Minimum := vector2{X := 0.0, Y := 1.0}, Maximum := vector2{X := 0.0, Y := 1.0}}
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 0.0, Y := 1.0}
                    SizeToContent := true
                    Widget := slider_regular:
                        DefaultValue := 5.0
                        DefaultMinValue := 0.0
                        DefaultMaxValue := 10.0
                        DefaultStepSize := 0.5
                canvas_slot: # 画面中央下, ColorBlock
                    Anchors := anchors{ Minimum := vector2{X := 0.5, Y := 1.0}, Maximum := vector2{X := 0.5, Y := 1.0}}
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 0.5, Y := 1.0}
                    SizeToContent := true
                    Widget := color_block:
                        DefaultColor := NamedColors.CornflowerBlue
                        DefaultOpacity := 1.0
                        DefaultDesiredSize := vector2{X := 128.0, Y := 128.0}
                canvas_slot: # 画面右下, Overlay
                    Anchors := anchors{Minimum := vector2{X := 1.0, Y := 1.0}, Maximum := vector2{X := 1.0, Y := 1.0}}
                    Offsets := margin{Top := 0.0, Left := 0.0, Right := 0.0, Bottom := 0.0}
                    Alignment := vector2{X := 1.0, Y := 1.0}
                    SizeToContent := true
                    Widget := overlay:
                        Slots := array:
                            overlay_slot:
                                Widget := color_block:
                                    DefaultColor := NamedColors.MintCream
                                    DefaultOpacity := 1.0
                                    DefaultDesiredSize := vector2{X := 1024.0, Y := 128.0}                                
                            overlay_slot:
                                Widget := text_block:
                                    DefaultText := TextForMyUI("This is my text block overlaying a color block.")
        
        return MyCanvas

UI作成の疑問

・UEFNのBluePrintから作成したUIをVerseで使用して動的に値を変更できるか?

現時点ではできなさそう
Can you access a created Widget BP within verse?
https://forums.unrealengine.com/t/can-you-access-a-created-widget-bp-within-verse/1192748

下記動画を参考にしてできそう
(別途解説記事を書こうと思います)
https://www.youtube.com/watch?v=GpcKRaDxe9g

その他参考URL

Custom UI / HUD
https://forums.unrealengine.com/t/custom-ui-hud/833768/13

Discussion