1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【UEFN】guard_actions_component の検証 - 前編

Last updated at Posted at 2025-12-14

はじめに

NPCのコンポーネント検証シリーズ、今回は npc_actions_component のサブクラスである guard_actions_component について調べました。

このコンポーネントを使うと、ガードNPC特有の「徘徊」「しゃがみ」「ジャンプ」といった、より人間らしい高度なアクションをVerseから制御できるようになります。

今回は前編として、以下の6つのアクションを検証しました。

RoamAround(周辺の徘徊)
MoveInRangeToAttack(射程内への移動:挙動確認中)
Crouch(しゃがみ)
⚠️ StandUp(立ち上がり:代替案あり)
Jump(ジャンプ)
PlayRandomEmote(ランダムエモート)

今回の検証では、一部のメソッドにおいて公式の意図通りに動作しない、あるいは発動条件が特定できないケースがありました。本記事では、現時点で判明した「動作する条件」と「挙動が不明だった点」をありのままにまとめています。

もし「こうすれば動いたよ!」という解決策をご存知の方がいれば、ぜひコメントで教えていただけると幸いです。

※本記事の内容は筆者の実験結果に基づく推測を含みます。今後のアップデートで挙動が変わる可能性がありますのでご注意ください。


環境:

  • UEFN: v39.10(UE 5.8)

guard_actions_component とは

v39.00 のリリース ノート で追加された、高度なガードAI用のコンポーネントです。

  • 特徴: 攻撃、障害物の飛び越え、蘇生など、従来のNPCより一歩踏み込んだ動作が可能になります。
  • 移行点: 従来の leashable インターフェースに代わるものとして導入されました。
API定義(guard_actions_component)
@available {MinUploadedAtFNVersion := 3900}
# Fortnite Guards AI actions management
guard_actions_component<native><public> := class<epic_internal>(npc_actions_component):
    # Roam around the current position. Use 'Tether' to specify the radius; otherwise, the Fortnite guard will roam anywhere.
    RoamAround<native><public>(?MovementType:movement_type = external {})<suspends>:result(void, ai_action_error_type)

    # Move in range to attack the current target.
    MoveInRangeToAttack<native><public>()<suspends>:result(void, ai_action_error_type)

    # Change stance to crouch. Will never complete unless interrupted.
    Crouch<native><public>()<suspends>:result(void, ai_action_error_type)

    # Go back to standing.
    StandUp<native><public>()<suspends>:result(void, ai_action_error_type)

    # Trigger a jump.
    Jump<native><public>()<suspends>:result(void, ai_action_error_type)

    # Play a random emote from the character emotes bank.
    PlayRandomEmote<native><public>()<suspends>:result(void, ai_action_error_type)

    # Revive the specified target.
    Revive<native><public>(Target:entity)<suspends>:result(void, ai_action_error_type)

    # Attack the target. The target must have been detected.
    Attack<native><public>(Target:entity)<suspends>:result(void, ai_action_error_type)

    # Tether the NPC to a position.
    #  'Radius' is in centimeters.
    Tether<native><public>(Location:(/Verse.org/SpatialMath:)vector3, Radius:float):void

    # Tether the NPC to an entity.
    #  'Radius' is in centimeters.
    Tether<native><public>(Target:entity, Radius:float):void

    # Untether the NPC.
    Untether<native><public>():void

事前設定(検証環境)

  • Island Settings: チームを FreeForAll に設定。
  • NPCキャラクター定義:
    • NPC Behavior Script: テンプレート「NPC Behavior Basic」を使用(変更なし)。
    • Team Modifier: Index 1 を指定。ソロプレイ時はNPCがプレイヤーの味方になります。
    • Guard Perception Modifier: デフォルト(オーバーライドなし)。

スクリーンショット 2025-12-14 221607.png


1. RoamAround

    # Roam around the current position. Use 'Tether' to specify the radius; otherwise, the Fortnite guard will roam anywhere.
    RoamAround<native><public>(?MovementType:movement_type = external {})<suspends>:result(void, ai_action_error_type)

# 現在の位置の周辺を徘徊します。'Tether'を使用して半径を指定します。指定しない場合、ガードはどこでも徘徊します。

MovementType の指定なし (= Running)

MovementType = Walking

  • 検証結果:
    • 徘徊させるには Tether()(係留設定) の実行が必須です。Tetherを設定しない場合、NPCはその場から動きませんでした
    • 引数の MovementType で歩き(Walking)か走り(Running)かを選択できます(デフォルトは Running)
検証用コード
    RoamAround_Test()<suspends>:void=
        Print("========== RoamAround_Test ==========")
        if(SimE := GetSimulationEntity[]):
            GuardActionsComps := for(Comp : SimE.FindDescendantComponents(guard_actions_component)){Comp}
            if(GuardActionsComp := GuardActionsComps[0]):
                TetherCenter := (/Verse.org/SpatialMath:)vector3{Left:=8456.0, Up:=0.0, Forward:=3340.0}
                TetherRadius := 512.0
                GuardActionsComp.Tether(TetherCenter, TetherRadius)
                # ※ デフォルトは Running
                GuardActionsComp.RoamAround()
                # GuardActionsComp.RoamAround(?MovementType:=movement_type.Walking)
                # GuardActionsComp.RoamAround(?MovementType:=movement_type.Running)
        Print("===============================================")

2. MoveInRangeToAttack

    # Move in range to attack the current target.
    MoveInRangeToAttack<native><public>()<suspends>:result(void, ai_action_error_type)

# 現在のターゲットを攻撃するための射程内に移動します。

  • 検証結果:
    • 目に見えるアクションは確認できませんでした
    • 攻撃アクション中に呼び出すと、攻撃を中断してその場に立ち止まるような動きが見られました
    • 推測: 単体で呼び出すのではなく、Attackと併用するなど、ほかに条件があるのかもしれません

3. Crouch

    # Change stance to crouch. Will never complete unless interrupted.
    Crouch<native><public>()<suspends>:result(void, ai_action_error_type)

# しゃがみ姿勢に変更します。中断されない限り完了しません。

  • 検証結果:

    • NPCがしゃがみ体勢になります
    • Crouch() 単体の実行では、NPCはしゃがみ姿勢になりません
      RouamAround() または、npc_actions_component.Idle() のあとに Crouch() を実行することで、NPCはしゃがみ状態へ移行しました
    • Crouch() 自体は中断されるまで完了しない( が終わらない)ため、race 式などで制御する必要があります
検証用コード
    # RoamAround() か Idle() を実行後、Crouch() を実行すると NPCはしゃがむ
    Crouch_Test()<suspends>:void=
        if(SimE := GetSimulationEntity[]):
            GuardActionsComps := for(Comp : SimE.FindDescendantComponents(guard_actions_component)){Comp}
            if(GuardActionsComp := GuardActionsComps[0]):
                Print("========== Crouch_Test ==========")
                GuardActionsComp.RoamAround()
                Print(" - RoamAround: End.")
                # GuardActionsComp.Idle(?Duration:=1.0)
                # Print(" - Idle: End1.")
                GuardActionsComp.Crouch()
                Print("===============================================")       

4. StandUp

    # Go back to standing.
    StandUp<native><public>()<suspends>:result(void, ai_action_error_type)

# 立ち上がります。

※ この動画は StandUp() ではない方法で立ち上がらせています

  • 検証結果:

    • Crouch() 実行中に、StandUp() を呼び出してもNPCは立ち上がりませんでした
      戻り値としてはエラーにならないものの、見た目はしゃがんだままです
    • 動画は、Idle() で立たせています。(検用証コード「StandUp_Test2()」)

【Tips】NPCを確実に立たせる方法
Crouch() と、 RoamAround() または npc_actions_component.Idle() を race することで、NPCは立ち上がります

検証用コード
    # Crouch() 実行中に、 StandUp() を実行する 
    # ⇒ 結果は エラーではないが、立ち上がらない
    StandUp_Test1()<suspends>:void=
        if(SimE := GetSimulationEntity[]):
            GuardActionsComps := for(Comp : SimE.FindDescendantComponents(guard_actions_component)){Comp}
            if(GuardActionsComp := GuardActionsComps[0]):
                Print("========== StandUp_Test1 ==========")
                race:
                    block:
                        GuardActionsComp.Idle(?Duration:=1.0)
                        Print(" - Idle: End1.")
                        GuardActionsComp.Crouch()
                        Print(" - Crouch: End.")

                    block:
                        # Crouch() 実行中に、StandUp() を実行するための待機
                        Sleep(3.0)
                        Result := GuardActionsComp.StandUp()
                        if(ErrorType := Result.GetError[]):
                            Print(" - StandUp: ErrorType: " + ToDiagnostic(ErrorType))
                        else:
                            Print(" - StandUp: Success")

                Print("===============================================") 


    # Crouch() 実行中に、 RoamAround() または Idle() を実行する 
    StandUp_Test2()<suspends>:void=
        if(SimE := GetSimulationEntity[]):
            GuardActionsComps := for(Comp : SimE.FindDescendantComponents(guard_actions_component)){Comp}
            if(GuardActionsComp := GuardActionsComps[0]):
                Print("========== StandUp_Test2 ==========")
                race:
                    block:
                        GuardActionsComp.Idle(?Duration:=1.0)
                        Print(" - Idle: End1.")
                        GuardActionsComp.Crouch()
                        Print(" - Crouch: End.")

                    block:
                        # Crouch() 実行中に、処理を実行するための待機
                        Sleep(3.0)
                        # # RoamAround() ⇒ 立ち上がる
                        # GuardActionsComp.RoamAround()
                        # Print(" - RoamAround: End.")
            
                        # Idle() ⇒ 立ち上がる
                        GuardActionsComp.Idle(?Duration:=1.0)
                        Print(" - Idle: End2.")

                Print("===============================================") 

5. Jump

    # Trigger a jump.
    Jump<native><public>()<suspends>:result(void, ai_action_error_type)

# ジャンプをトリガーします。

  • 検証結果:
    • NPCがその場で1回ジャンプします
    • 着地したタイミングで Jump() の処理が終了します
検証用コード
    Jump_Test()<suspends>:void=
        if(SimE := GetSimulationEntity[]):
            GuardActionsComps := for(Comp : SimE.FindDescendantComponents(guard_actions_component)){Comp}
            if(GuardActionsComp := GuardActionsComps[0]):
                Print("========== Jump_Test ==========")
                GuardActionsComp.Jump()
                Print("===============================================") 

6. PlayRandomEmote

    # Play a random emote from the character emotes bank.
    PlayRandomEmote<native><public>()<suspends>:result(void, ai_action_error_type)

# キャラクターのエモートバンクからランダムなエモートを再生します。

  • 検証結果:
    • 一度開始すると、そのエモートを繰り返します。自動で終了することはありませんでした
    • race 式を使い、一定時間後に他のアクションを割り込ませることで終了可能です
検証用コード
    PlayRandomEmote_Test1()<suspends>:void=
        if(SimE := GetSimulationEntity[]):
            GuardActionsComps := for(Comp : SimE.FindDescendantComponents(guard_actions_component)){Comp}
            if(GuardActionsComp := GuardActionsComps[0]):
                Print("========== PlayRandomEmote_Test ==========")
                GuardActionsComp.PlayRandomEmote()
                Print("===============================================") 

後編に続きます。


関連記事

1
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?