[UEFN][Verse][ビルドエラー] Script error 3512: This invocation calls a function that has the ‘suspends’ effect, which is not allowed by its context.

目次

ビルドエラー

下記のエラーメッセージがでました。

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

プログラムソース

プログラムの中で、エラーが出た原因箇所をコメントで「!!!!!!!!!!!!!!!!!」と記載してます。

※作りかけのプログラムなので、全体的には半端な状態です。


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

# See https://dev.epicgames.com/documentation/en-us/uefn/create-your-own-device-in-verse for how to create a verse device.

# A Verse-authored creative device that can be placed in a level
player_camera_device := class(creative_device):
    # カメラ
    @editable
    Camera1Container : creative_prop = creative_prop{}
    # カメラのオンオフを切り替えるボタン
    @editable
    CameraOnOffButton : button_device = button_device{}
    # ムービーシーケンスの仕掛け
    @editable
    SequenceDevice : cinematic_sequence_device = cinematic_sequence_device{}
    # 全プレイヤーの配列格納用
    var Players : []player = array{}
    # カメラモードのフラグ [true: カメラオン, false: カメラオフ]
    var CameraOnOffFlag : logic = false

    # 初期化
    InitCamera() : void =
        # 変数に初期値を格納
        set Players = GetPlayspace().GetPlayers()
        set CameraOnOffFlag = false
        # カメラのオンオフを切り替えるボタンの処理を登録
        # !!!!!!!!!!!!!!!!! Subscribe で登録している CameraOnOff 関数がエラーの要因 !!!!!!!!!!!!!!!!!
        CameraOnOffButton.InteractedWithEvent.Subscribe(CameraOnOff)
        # !!!!!!!!!!!!!!!!! Subscribe で登録している CameraOnOff 関数がエラーの要因 !!!!!!!!!!!!!!!!!
        return

    # カメラのオンオフの切り替え
    CameraOnOff(InPlayer : agent) : void =
        # カメラオンオフフラグを更新
        if(CameraOnOffFlag?):
            set CameraOnOffFlag = false
        else:
            set CameraOnOffFlag = true
        
        if(CameraOnOffFlag?):
            # カメラを動かす
            # !!!!!!!!!!!!!!!!! MoveCamera 内の処理がエラーの要因 !!!!!!!!!!!!!!!!!
            MoveCamera()
            # !!!!!!!!!!!!!!!!! MoveCamera 内の処理がエラーの要因 !!!!!!!!!!!!!!!!!
            # TODO: ここにカメラ起動の処理
        else:
            # TODO: ここにカメラ停止の処理
        return

    # カメラを動かす
    MoveCamera()<suspends> : void =
        # 最初のプレイヤーの有無をチェック
        if (Player := Players[0], FortCharacter := Player.GetFortCharacter[]):
            # カメラ位置を計算
            PlayerPosition := FortCharacter.GetTransform().Translation
            Camera1Position := Camera1Container.GetTransform().Translation
            diffPos := PlayerPosition - Camera1Position
            # カメラ角度を計算
            Angle := ArcTan(diffPos.X, diffPos.Y) - 3.14 / 2.0
            # カメラ設置位置を確定
            NewRotation := MakeRotation( vector3{ X := 0.0, Y := 0.0, Z := 0.0}, Angle)
            # カメラを移動
            # !!!!!!!!!!!!!!!!! MoveTo がエラーの要因 !!!!!!!!!!!!!!!!!
            Camera1Container.MoveTo(PlayerPosition, NewRotation, 0.01)
            # !!!!!!!!!!!!!!!!! MoveTo がエラーの要因 !!!!!!!!!!!!!!!!!
        return

    # Runs when the device is started in a running game
    OnBegin<override>()<suspends>:void=
        InitCamera()

解消方法

ビルでエラーの原因となっている suspends な関数呼び出しを spawn{} で囲むとビルドエラーがでなくなりました。

修正した箇所をコメントで「!!!!!!!!!!!!!!!!!」と記載してます。


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

# See https://dev.epicgames.com/documentation/en-us/uefn/create-your-own-device-in-verse for how to create a verse device.

# A Verse-authored creative device that can be placed in a level
player_camera_device := class(creative_device):
    # カメラ
    @editable
    Camera1Container : creative_prop = creative_prop{}
    # カメラのオンオフを切り替えるボタン
    @editable
    CameraOnOffButton : button_device = button_device{}
    # ムービーシーケンスの仕掛け
    @editable
    SequenceDevice : cinematic_sequence_device = cinematic_sequence_device{}
    # 全プレイヤーの配列格納用
    var Players : []player = array{}
    # カメラモードのフラグ [true: カメラオン, false: カメラオフ]
    var CameraOnOffFlag : logic = false

    # 初期化
    InitCamera() : void =
        # 変数に初期値を格納
        set Players = GetPlayspace().GetPlayers()
        set CameraOnOffFlag = false
        # カメラのオンオフを切り替えるボタンの処理を登録
        CameraOnOffButton.InteractedWithEvent.Subscribe(CameraOnOff)
        return

    # カメラのオンオフの切り替え
    CameraOnOff(InPlayer : agent) : void =
        # カメラオンオフフラグを更新
        if(CameraOnOffFlag?):
            set CameraOnOffFlag = false
        else:
            set CameraOnOffFlag = true
        
        if(CameraOnOffFlag?):
            # カメラを動かす
            # !!!!!!!!!!!!!!!!! spawn{} で suspends の関数を囲む !!!!!!!!!!!!!!!!!
            spawn{MoveCamera()}
            # !!!!!!!!!!!!!!!!! spawn{} で suspends の関数を囲む !!!!!!!!!!!!!!!!!
            # TODO: ここにカメラ起動の処理
        else:
            # TODO: ここにカメラ停止の処理
        return

    # カメラを動かす
    MoveCamera()<suspends> : void =
        # 最初のプレイヤーの有無をチェック
        if (Player := Players[0], FortCharacter := Player.GetFortCharacter[]):
            # カメラ位置を計算
            PlayerPosition := FortCharacter.GetTransform().Translation
            Camera1Position := Camera1Container.GetTransform().Translation
            diffPos := PlayerPosition - Camera1Position
            # カメラ角度を計算
            Angle := ArcTan(diffPos.X, diffPos.Y) - 3.14 / 2.0
            # カメラ設置位置を確定
            NewRotation := MakeRotation( vector3{ X := 0.0, Y := 0.0, Z := 0.0}, Angle)
            # カメラを移動
            Camera1Container.MoveTo(PlayerPosition, NewRotation, 0.01)
        return

    # Runs when the device is started in a running game
    OnBegin<override>()<suspends>:void=
        InitCamera()

解説、というよりは所感

私なりの解釈を述べますが、UEFN も Verse もドキュメントを読み始めて間もないので、いまいち私の理解が合っているか自信がないことはご留意ください。

非同期(async )処理を含む関数は suspends 関数という一時停止する関数という扱いになる、のだと思われます。

そして、button_device の InteractedWithEvent.Subscribe() でボタンに suspends 関数は登録できないみたいです。

なので suspends 関数でない関数で、suspends 関数をラップして、それをイベント登録することになるのですが、そうすると今度は「suspends 関数じゃないのに内部で suspends 関数呼び出してるよ」という旨のビルドエラーになります。(これが本件のビルドエラー、のはず)

ドキュメントを探したところ、非 suspends 関数で非同期(async )処理を呼び出す際には spawn 式を使う必要があるみたいです。

よかったらシェアしてね!
目次