はじめに
こんにちは、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式の処理フローはこちら。
図の引用: https://dev.epicgames.com/documentation/ja-jp/uefn/spawn-in-verse