🔧

[Verse]Subscribeのコールバックにパラメータを追加してみた!

2024/09/25に公開

やりたいこと

listenableなイベントのSubscribeメソッドに渡されるコールバックはペイロードの型のパラメータしか受け取れないため、コールバックに任意の型のパラメータを追加できるような実装を考えてみました。
やってることとしてはこちらの記事とあまり変わらないのですが、相互依存の解消とパラメトリック型を使用することで抽象度を上げています。抽象度を上げることで、追加したい型とペイロードの型のさまざまな組み合わせでも使いやすくなるように実装しています。

動画

https://youtu.be/4QlRjPuNu24?si=qL9R7VlCWUxA2lcr

全体のコード

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

ToMessage<localizes>(Text : string)<computes> : message = "{Text}"

button_management_device := class(creative_device):
    @editable
    Buttons : []button_device = array{}

    OnBegin<override>()<suspends>:void=
        for:
            Index -> Button : Buttons
            CstmCallback := custom_callback(string, agent):
                Value := "Button{Index} Clicked!"
                Callback := OnInteracted
        do:
            Button.InteractedWithEvent.Subscribe(CstmCallback.Invoke)

    OnInteracted<private>(Str : string, Agent : agent) : void =
        if (PlayerUI := GetPlayerUI[player[Agent]]):
            Widget := CreateWidget(Str)
            PlayerUI.AddWidget(Widget)
            spawn{ DelayedRemoveWidget(PlayerUI, Widget) }

    DelayedRemoveWidget<private>(PlayerUI : player_ui, Widget : widget)<suspends> : void =
        Sleep(3.0)
        PlayerUI.RemoveWidget(Widget)

    CreateWidget<private>(Str : string) : widget =
        return canvas:
            Slots := array:
                canvas_slot:
                    Anchors := anchors:
                        Minimum := vector2{X := 0.5, Y := 0.6}
                        Maximum := vector2{X := 0.5, Y := 0.6}
                    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 := text_block{ DefaultText := ToMessage(Str) }
custom_callback.verse
CustomCallback<public> := module:
    custom_callback<public>(t1:type, t2:type) := class:
        Value<public> : t1
        Callback<public> : tuple(t1, t2) -> void

        Invoke<public>(Payload : t2) : void = Callback(Value, Payload)

解説

custom_callbackクラスのt1の型には追加したいパラメータの型をt2にはイベントのペイロードの型を入れます。

button_management_device.verse
    OnBegin<override>()<suspends>:void=
        for:
            Index -> Button : Buttons
                            #t1にstring型、t2にagent型を指定
            CstmCallback := custom_callback(string, agent):
                Value := "Button{Index} Clicked!" #追加のパラメータ
                Callback := OnInteracted
        do:
            #button_deviceクラスのInteractedWithEventのペイロードはagent型
            Button.InteractedWithEvent.Subscribe(CstmCallback.Invoke)

今回の場合はstring型のパラメータを追加したいので、t1にstring型、t2にbutton_deviceクラスのInteractedWithEventのペイロードであるagent型を指定しています。

Discussion