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】npc_actions_component の検証 - 前編 (移動関連編)

1
Last updated at Posted at 2025-12-06

はじめに

UEFN (Verse) の npc_actions_component について、公式ドキュメントがまだ充実していないため、実際にコードを動かして挙動を検証しました。 機能が多岐にわたるため、今回は 「移動(Navigation)」 に関連する以下の機能に絞って紹介します。

  1. GetCurrentDestination: 現在の目的地の取得

  2. NavigateTo: 特定の場所への移動

  3. MovementSpeedMultiplier: 移動速度の変更

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

環境:
Fortnite v39.00 (UE 5.8)

npc_actions_component とは

NPC の行動を制御するためのコンポーネントです。 NPC を特定の位置へ移動させたり、視線を制御したりすることができます。

API定義: npc_actions_component
@available {MinUploadedAtFNVersion := 3900}
# Fortnite NPC AI actions management
npc_actions_component<native><public> := class<final_super><epic_internal>(component):
    # Return the current destination of the character.
    GetCurrentDestination<native><public>()<transacts><decides>:(/Verse.org/SpatialMath:)vector3

    # Navigate toward the specified navigation target.
    NavigateTo<native><public>(Target:navigation_target, ?MovementType:movement_type = external {}, ?ReachRadius:float = external {}, ?AllowPartialPath:logic = external {})<suspends>:result(navigation_action_success_type, navigation_action_error_type)

    # Multiplier on the movement speed (value is clamped between 0.5 and 2).
    var MovementSpeedMultiplier<public>:float = external {}

    # Stop navigation.
    StopNavigation<native><public>():void

    # Stay idle for a specific duration.
    Idle<native><public>(?Duration:float = external {})<suspends>:void

    # Look at the specified location. If LockFocus is false, the action stops once the NPC is facing the position.
    Focus<native><public>(Location:(/Verse.org/SpatialMath:)vector3, ?LockFocus:logic = external {})<suspends>:void

    # Look at the specified Entity. If LockFocus is false, the action stops once the NPC is facing the entity.
    Focus<native><public>(Target:entity, ?LockFocus:logic = external {})<suspends>:void

1. GetCurrentDestination

# Return the current destination of the character.
GetCurrentDestination<native><public>()<transacts><decides>:(/Verse.org/SpatialMath:)vector3

# キャラクターの現在の目的地を返します。

検証結果

  • 戻り値は「直近の経由地点」
    NavigateTo() で指定したターゲット(最終目的地)ではなく、ナビゲーションメッシュ上の「現在向かっている中継地点(パス上の次のポイント)」の座標が返ってくるようです。

  • 実行タイミング
    移動(NavigateTo())が開始される前に呼び出すと失敗します。

NPCのナビゲーションにおける目的地(Destination)のイメージ

ターゲット(最終目的地)に向かうための、現在目指している中継地点が取得できます。

NPCが3つの黄色い人形を順番に移動します。GetCurrentDestination[] で取得した座標に、ピンクの人形を毎秒テレポートさせています。
黄色い人形(最終目的地)へ向かうルート上の、少し手前の位置(現在向かっている場所)にピンクの人形がテレポートしていることがわかります。

検証用コード
    # 現在の目的地を取得するテスト
    GetCurrentDestination_Test(Agent:agent)<suspends>:void=
        Print("========== GetCurrentDestination_Test ==========")
        if(SimE := GetSimulationEntity[]):
            # SimulationEntity 以下にある npc_actions_component を1つ取得
            NPCActionsComps := for(Comp : SimE.FindDescendantComponents(npc_actions_component)){Comp}
            if(NPCActionsComp := NPCActionsComps[0]):

                sync:
                    block:
                        # 3秒待機後に NavigateTo を実行。3箇所に移動する
                        Sleep(3.0)
                        for(X := 0..2, NavTargetProp := NavTargetProps[X]):
                            TargetPosUE := NavTargetProp.GetTransform().Translation
                            TargetPosVerse := FromVector3(TargetPosUE)
                            Print("-----------------------------------------------")
                            Print(" - NavigateTo[{X}] TargetPosition: {TargetPosVerse}")
                            # UEモジュール, Verseモジュール どちらのvector3でもOK
                            NPCActionsComp.NavigateTo(MakeNavigationTarget((TargetPosVerse)))
                        
                        Print(" - NavigateTo tests done.")
                        Print("-----------------------------------------------")

                    block:
                        # 20秒間 GetCurrentDestination[] を計測
                        for(X := 0..20):
                            Sleep(1.0)
                            if(Destination := NPCActionsComp.GetCurrentDestination[]):
                                Print(" - GetCurrentDestination: {Destination}")

                                # Destination の位置をマップ内で確認するため、 Prop をテレポート                 
                                DestinationUE := FromVector3(Destination)
                                Rot := (/UnrealEngine.com/Temporary/SpatialMath:)IdentityRotation()
                                if(CurrentDestinationProp.TeleportTo[DestinationUE, Rot]){}

                            # 📝: NavigatoToが開始前は失敗。 
                            else:
                                Print(" - GetCurrentDestination: 失敗. ")
                        Print(" - GetCurrentDestination tests done.")

        Print("===============================================")
ログ ``` ========== GetCurrentDestination_Test ========== - GetCurrentDestination: 失敗. - GetCurrentDestination: 失敗. ----------------------------------------------- - NavigateTo[0] TargetPosition: {Forward = -768.000000, Left = 0.000000, Up = 0.000000} - GetCurrentDestination: 失敗. - GetCurrentDestination: {Forward = -672.000000, Left = 0.000000, Up = 8.000000} - GetCurrentDestination: {Forward = -672.000000, Left = 0.000000, Up = 8.000000} ----------------------------------------------- - NavigateTo[1] TargetPosition: {Forward = 768.000000, Left = 0.000000, Up = 0.000000} - GetCurrentDestination: {Forward = 504.000000, Left = 0.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 504.000000, Left = 0.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 504.000000, Left = 0.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 504.000000, Left = 0.000000, Up = 8.000000} ----------------------------------------------- - NavigateTo[2] TargetPosition: {Forward = 0.000000, Left = -1280.000000, Up = 0.000000} - GetCurrentDestination: {Forward = 720.000000, Left = -72.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 504.000000, Left = -504.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 36.371134, Left = -1224.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 36.371134, Left = -1224.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 0.000000, Left = -1280.000000, Up = 8.000000} - NavigateTo tests done. ----------------------------------------------- - GetCurrentDestination: {Forward = 0.000000, Left = -1280.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 0.000000, Left = -1280.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 0.000000, Left = -1280.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 0.000000, Left = -1280.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 0.000000, Left = -1280.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 0.000000, Left = -1280.000000, Up = 8.000000} - GetCurrentDestination: {Forward = 0.000000, Left = -1280.000000, Up = 8.000000} - GetCurrentDestination tests done. =============================================== ```

2. NavigateTo

# Navigate toward the specified navigation target.
NavigateTo<native><public>(Target:navigation_target, ?MovementType:movement_type = external {}, ?ReachRadius:float = external {}, ?AllowPartialPath:logic = external {})<suspends>:result(navigation_action_success_type, navigation_action_error_type)

# 指定されたナビゲーションターゲットに向かって移動します。

NPCを指定したターゲット(座標 または agent)に向かって移動させます。
NavigateTo() でナビゲーションが終了すると、成功であれば成功のタイプが、エラーであればエラーのタイプが戻ってきます。result(navigation_action_success_type, navigation_action_error_type)

結果の確認方法は、ページ下部のコードをご参照ください
付録:検証に使用したログ出力関数

ReachRadius (到達判定半径)

ReachRadius を設定すると、ターゲットの中心まで行かずとも、指定した半径内に入れば「到達した」とみなされます。

  • 検証: ReachRadius:=256.0 に設定

  • 結果: 黄色の人形(ターゲット)の手前で立ち止まり、次のアクションへ移行しました

検証用コード
    # ReachRadius オプションのテスト
    NavigateTo_Test2()<suspends>:void=
        Print("========== NavigateTo_Test2 ==========")
        if(SimE := GetSimulationEntity[]):
            NPCActionsComps := 
                for(Comp : SimE.FindDescendantComponents(npc_actions_component)){Comp}
            if(NPCActionsComp := NPCActionsComps[0]):
                Target1 := MakeNavigationTarget(
                    (/Verse.org/SpatialMath:)vector3{Left:=0.0, Up:=0.0, Forward:=-768.0}) 
                Result1 := NPCActionsComp.NavigateTo(Target1, ?ReachRadius:=256.0)
                PrintNavActionResult(Result1)

                Target2 := MakeNavigationTarget(
                    (/Verse.org/SpatialMath:)vector3{Left:=0.0, Up:=0.0, Forward:=768.0}) 
                Result2 := NPCActionsComp.NavigateTo(Target2, ?ReachRadius:=256.0)
                PrintNavActionResult(Result2)
        Print("===============================================")
ログ
========== NavigateTo_Test2 ==========
 - NavigateTo: GetSuccess[] (/Fortnite.com/AI:)navigation_action_success_type.Reached
 - NavigateTo: GetError[] Failed.
 - NavigateTo: GetSuccess[] (/Fortnite.com/AI:)navigation_action_success_type.Reached
 - NavigateTo: GetError[] Failed.
===============================================

AllowPartialPath (不完全なパスの許可)

目的地が「到達不可能な場所(例:屋根の上など)」にある場合の挙動を制御します。
動画では、ターゲットを同じにして、 AllowPartialPath を変更して検証しました。ターゲットは、ピンクの人形がある位置です。

AllowPartialPath = true の場合

「行けるところまで行く」設定と考えられます。

  • 挙動: 屋根の下で壁にぶつかるまで移動してから止まりました

  • 結果: エラー navigation_action_error_type.Blocked が返されました

AllowPartialPath = false の場合

「完全に到達できないなら動かない」設定と考えられます。

  • 挙動: その場から一歩も動きませんでした

  • 結果: エラー navigation_action_error_type.Invalid が返されました

検証用コード
    # AllowPartialPath オプションの違いをテスト(true)
    NavigateTo_Test3a()<suspends>:void=
        Print("========== NavigateTo_Test3a ==========")
        if(SimE := GetSimulationEntity[]):
            NPCActionsComps := 
                for(Comp : SimE.FindDescendantComponents(npc_actions_component)){Comp}
            if(NPCActionsComp := NPCActionsComps[0]):
                
                FarPos := (/Verse.org/SpatialMath:)vector3{
                    Left := -192.0, 
                    Up := 1180.0, 
                    Forward := 5784.0
                }
                Print("--- Test: 遠い地点 (AllowPartialPath = true) ---")
                Result := NPCActionsComp.NavigateTo(
                    MakeNavigationTarget(FarPos), 
                    ?AllowPartialPath := true
                )
                PrintNavActionResult(Result)

        Print("===============================================")
        
    # AllowPartialPath のオプション違いをテスト(false)
    NavigateTo_Test3b()<suspends>:void=
        Print("========== NavigateTo_Test3b ==========")
        if(SimE := GetSimulationEntity[]):
            NPCActionsComps := 
                for(Comp : SimE.FindDescendantComponents(npc_actions_component)){Comp}
            if(NPCActionsComp := NPCActionsComps[0]):
                
                FarPos := (/Verse.org/SpatialMath:)vector3{
                    Left := -192.0, 
                    Up := 1180.0, 
                    Forward := 5784.0
                }                
                Print("--- Test : 遠い地点 (AllowPartialPath = false) ---")
                Result := NPCActionsComp.NavigateTo(
                    MakeNavigationTarget(FarPos), 
                    ?AllowPartialPath := false
                )
                PrintNavActionResult(Result)

        Print("===============================================")
ログ
========== NavigateTo_Test3a ==========
--- Test: 遠い地点 (AllowPartialPath = true) ---
 - NavigateTo: GetSuccess[] Failed.
 - NavigateTo: GetError[] (/Fortnite.com/AI:)navigation_action_error_type.Blocked
===============================================
========== NavigateTo_Test3b ==========
--- Test : 遠い地点 (AllowPartialPath = false) ---
 - NavigateTo: GetSuccess[] Failed.
 - NavigateTo: GetError[] (/Fortnite.com/AI:)navigation_action_error_type.Invalid
===============================================


3. MovementSpeedMultiplier

# Multiplier on the movement speed (value is clamped between 0.5 and 2).
var MovementSpeedMultiplier<public>:float = external {}

# 移動速度の倍率(値は0.5から2の間にクランプされます)。


検証結果

  • NavigateTo() で移動中でも、動的に速度を変更することが可能です

  • 動画では 0.5倍(歩き)と 2.0倍(走り)が交互に切り替わっている様子が確認できます

コード
    # MovementSpeedMultiplier の変更テスト
    NavigateTo_Test4()<suspends>:void=
        Print("========== MovementSpeedMultiplier ==========")
        if(SimE := GetSimulationEntity[]):
            NPCActionsComps := for(Comp : SimE.FindDescendantComponents(npc_actions_component)){Comp}
            if(NPCActionsComp := NPCActionsComps[0]):
                race:
                    block:
                        # NavigateTo で3箇所に順番に移動する
                        loop:
                            for(X := 0..2, NavTargetProp := NavTargetProps[X]):
                                TargetPos := NavTargetProp.GetTransform().Translation
                                Print("-----------------------------------------------")
                                Print(" - NavigateTo[{X}] TargetPosition: {TargetPos}")
                                NPCActionsComp.NavigateTo(MakeNavigationTarget((TargetPos)))
                            Sleep(0.5)
                        Print(" - NavigateTo tests done.")
                        Print("-----------------------------------------------")
                    block:
                        # 3秒おきに移動速度を切り替える
                        for(X := 0..4):
                            if(NPCActionsComp.MovementSpeedMultiplier = 0.5):
                                set NPCActionsComp.MovementSpeedMultiplier = 2.0

                            else:
                                set NPCActionsComp.MovementSpeedMultiplier = 0.5
                            Sleep(2.0)
                            Print(" - MovementSpeedMultiplier: {NPCActionsComp.MovementSpeedMultiplier}")
                        Print(" - MovementSpeedMultiplier tests done.")
        Print("===============================================")

付録:検証に使用したログ出力関数

NavigateTo() の結果(result) を確認するための、ヘルパー関数です

# NavigateTo の結果をログに出力する関数
# - 成功(GetSuccess[]に成功)の場合、 navigation_action_success_type を出力
# - エラー(GetError[]に成功)の場合、 navigation_action_error_type を出力
PrintNavActionResult(NavActionResult:result(navigation_action_success_type, navigation_action_error_type))<suspends>:void=
    if(SuccessType := NavActionResult.GetSuccess[]):
        Print(" - NavigateTo: GetSuccess[] " + ToDiagnostic(SuccessType))
    else:
        Print(" - NavigateTo: GetSuccess[] Failed.")

    if(ErrorType := NavActionResult.GetError[]):
        Print(" - NavigateTo: GetError[] " + ToDiagnostic(ErrorType))
    else:
        Print(" - NavigateTo: GetError[] Failed.")

まとめと次回

今回は npc_actions_component の移動機能を中心に検証しました。 特に NavigateTo() の戻り値や AllowPartialPath による挙動の違いは、ゲームロジックを組む上でのポイントになりそうです。

次回(後編)では、残りの関数について検証します。

  • StopNavigation

  • Idle

  • Focus

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?