LoginSignup
0
0

[UEFN][Verse]非同期関数の呼び出しをイベントにバインドされた関数から呼び出す

Posted at

はじめに

こんにちは、XRエンジニアのイワケンです。最近はUEFNとVerse言語を触っています。

最近Verseでこんな処理を書きたいときがありました。

  • Buttonを押したら、毎秒ごとにコインをGetするシステムを起動する

そのために以下のコードを書いたのですが、エラーがでました。


using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

coin_system_device := class(creative_device):

    #ButtonをEditorから参照できるようにする
    @editable
    StartCoinSystemButton:button_device = button_device{}

    OnBegin<override>()<suspends>:void=
        OnStartIncomeButton.InteractedWithEvent.Subscribe(OnTriggerStart)

    #Buttonが押されたら呼び出す関数
    OnTriggerStart(Agent:agent):void=
        LaunchGetCoinSystem(Agent) #この文がエラーが出る

    #1秒ごとにコインを付与するloop実装を始める関数
    LaunchGetCoinSystem(Agent:agent)<suspends>:void=
        loop:
            Sleep(1.0)
            GiveCoin(Agent) #コインを付与する実装、中身は今回省略
    

LaunchGetCoinSystem(Agent)の行に次のようなエラーがでます。

This invocation calls a function that has the 'suspends' effect, which is not allowed by its context.(3512)

日本語訳で

この呼び出しは、そのコンテキストで許可されていない「suspends」効果を持つ関数を呼び出している(3512)。

suspendsとは、エフェクト指定子の一つであり、 関数が非同期であることを示します。また関数本体の async コンテキストを作成します。(参考ドキュメント)

つまり、非同期関数であるLaunchGetCoinSystem関数をどうにかする必要があります。

結論 spawnを使う

結果次のようなコードで解決
spawn{}で非同期関数を囲います。その事により、async以外の関数で呼び出すことができます。(参考ドキュメント)

    #Buttonが押されたら呼び出す関数
    OnTriggerStart(Agent:agent):void=
        spawn{LaunchGetCoinSystem(Agent)}

Verse言語の並列処理に関して少し調べる

これらを理解するために、Verse言語の並列処理に関してのお作法を紹介します (理解している範囲で)

asyncコンテキストとsuspendsエフェクト指定子

Verseの式(expression)はimmediateとasyncのいづれかになります。つまり、遅延なく評価される式(immediate)か、評価に時間がかかる可能性がある式 (async)です。

このasync式は、asyncコンテキストを持つ場所じゃないと使えません。asyncコンテキストを持つ場所が、suspendsエフェクト指定子を持つ関数の本体です。

先程のエラー文は「suspendsエフェクト指定子を持たない関数」の中で、async式を呼ぼうとしたのでエラーが出たのです。
じゃあ、「OnTriggerStart関数をsuspendsつければいいじゃない?」と思うのですが、button_deviceのイベントにバインドしているためそれができないのです。

spawn式はasync関数をasyncコンテキスト外でも呼び出せる

spawn式の特徴は

  • ①async関数を呼び出せる
  • ②asyncコンテキストの内側、外側どちらでも呼び出せる
  • ③spawn式の後ろの式は、spawn式の評価を待たずに実行される

並列処理、非同期処理を扱える式がいくつかあるのですが、asyncコンテキストの外側で実行できる式はspawn式だけです。(参考ドキュメント)

ただし③の特徴のように、評価の結果を待たないため、結果を待つ処理をしたい場合は、asyncコンテキストの中で別の非同期処理を扱うコードを書く必要がありそうです。

spawn式の処理フローはこちら。

image.png
図の引用: https://dev.epicgames.com/documentation/ja-jp/uefn/spawn-in-verse

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0