AddWidgetでUI表示

GetPlayerUI<native><public>(Player:player)<transacts><decides>:player_ui

# The main interface for adding and removing `widget`s to a player's UI.
player_ui<native><public> := class<final><epic_internal>:
    # Adds `Widget` to this `player_ui` using default `player_ui_slot` configuration options.
    AddWidget<native><public>(Widget:widget):void

    # Adds `Widget` to this `player_ui` using `Slot` for configuration options.
    AddWidget<native><public>(Widget:widget, Slot:player_ui_slot):void

    # Removes `Widget` from this `player_ui`.
    RemoveWidget<native><public>(Widget:widget):void

    # Sets the user's focus on this `Widget`. The target `Widget`must be focusable, otherwise this has no effect.
    # If `SetFocus` is called before `AddWidget`, the `widget` will be focused after `AddWidget` is called, 
    # unless a SetFocus is called on a different `widget` by the time `AddWidget` is called.
    SetFocus<native><public>(Widget:widget):void

UnrealEngine.digestには上記のような関数とクラスが定義されています。Verse由来のUIとウィジェットブループリントの両方は、このクラスを経由して表示/非表示を管理します。

GetPlayerUI

「GetPlayerUI」関数を使用することで、プレイヤーのUI情報を管理するクラスである「player_ui」にアクセスできます。

# 例1
if:
    PlayerUI := GetPlayerUI[Player]
then:

# 例2
OnInteract(Agent:agent):void=
    if:
        Player := player[Agent]
        PlayerUI := GetPlayerUI[Player]
    then:

GetPlayerUIの引数には「player型」のクラスを入れます。多くの場合、仕掛けのイベントからプレイヤー自身でもある「agent」クラスにアクセスできるので、それを「player[agent]」とキャストして、GetPlayerUIの引数に渡します。

当然ですが、NPCや野生動物のようなagentはplayerではありませんので、このifは失敗します。

二つのAddWidgetと二つのモード

player_uiクラスには、引数が一つの「AddWidget」と、引数が二つの「AddWidget」が存在しています。

AddWidgetの引数には「widgetクラス」が求められており、これは「canvas」や「Assets.digest」からアクセスできるウィジェットブループリントはwidgetクラスを継承しているため、引数に入れることができます(当然、今あげたもの以外もwidgetクラスを継承していればなんでも入れられます)

NewCanvas := canvas:
    Slots := array:
        # canvas_slotを記述

PlayerUI.AddWidget(NewCanvas)

のように、ウィジェットを入れることができます。引数が一つのAddWidgetは、「ui_input_mode」が「None」の状態でUIの表示がされます。これは、キャラクターの操作やカメラの移動に影響させない、情報を表示させるだけのUIを作り出せます。

PlayerUI.AddWidget(NewCanvas, player_ui_slot{InputMode := ui_input_mode.All})

と、第二引数にplayer_ui_slotクラスを入れてあげ、InputModeに「ui_input_mode.All」の指定をしてあげると、UIボタンやスライダーのような要素を操作できる、インタラクト可能なUIを表示できます。

PlayerUI.AddWidget(NewCanvas, player_ui_slot{InputMode := ui_input_mode.None})

ちなみに、Noneとすれば、第二引数を省略したAddWidgetと同じく「UIボタンやスライダーを触れない」UIとなります。これは、単純に省略したか、きちんと明示して書くかの違いです。

UI非表示

var CurrentCanvas:?widget = false

ShowUI(Player:player):void=
    if:
        PlayerUI := GetPlayerUI[Player]
    then:
        NewCanvas := canvas:
            Slots := array:
                # UI要素を記述

        PlayerUI.AddWidget(NewCanvas)
        set CurrentCanvas = option{NewCanvas}

HideUI(Player:player):void=
    if:
        Canvas := CurrentCanvas?
        PlayerUI := GetPlayerUI[Player]
    then:
        PlayerUI.RemoveWidget(Canvas)
        set CurrentCanvas = false

RemoveWidget機能を使用することで、UIを非表示することができます。

注意点として「表示したときと同じクラスのインスタンス」を入れてあげる必要があります。

# ダメな例

Canvas := canvas:
    Slots := array:
        # UI要素を記述

PlayerUI.AddWidget(Canvas)

NewCanvas := canvas:
    Slots := array:
        # UI要素を記述

PlayerUI.RemoveWidget(NewCanvas)

例えば、RemoveWidgetを呼び出す際に新しくcanvasクラスを作成し、RemoveWidgetに入れたとしても、UI要素は非表示になりません。

見た目は同じ構成で同じクラスを入れているようですが、中身は別のタイミングで作成した別のクラスなので、Verse側で現在表示中のUIとは別物として判定されるからです。

この辺の概念が難しい…という方は、今の段階で無理に理解しなくても問題ないです!残りのチャプターを進めていくと、自然と理解が深まっていくと思いますので…。