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?

はじめに

NPCのコンポーネント検証シリーズ、今回は npc_awareness_component について調べました。

このコンポーネントは、NPCの「知覚(視覚・聴覚・触覚)」を司る中枢です。ターゲットを検知した瞬間や、見失った瞬間のイベントをフックにすることで、NPCのAI挙動をVerseから細かく制御できるようになります。

今回は、主要なプロパティと5つのイベントについて検証しました。

  ✅ DetectedTargets(検知済みターゲットのリスト)
  ✅ DetectTargetEvent(ターゲット検知イベント)
  ✅ ForgetTargetEvent(ターゲットを忘れるイベント)
  ✅ SeeTargetEvent(視覚検知イベント)
  ✅ HearTargetEvent(聴覚検知イベント)
  ✅ TouchTargetEvent(触覚検知イベント)

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

環境:

UEFN: v39.10(UE 5.8)

npc_awareness_component とは

v39.00 のリリース ノート で追加された、NPCの知覚(Perception)を一括管理するためのコンポーネントです。

ターゲットを「見つけた」「聞いた」「触れた」といった情報をイベントとして受け取れます。

API定義(npc_awareness_component)
@available {MinUploadedAtFNVersion := 3900}
# Fortnite NPC perception management
npc_awareness_component<native><public> := class<final_super><epic_internal>(component):
    # Information about all detected targets.
    var<private> DetectedTargets<native><public>:[]npc_target_info = external {}

    # Event when a target was detected.
    DetectTargetEvent<native><public>:listenable(npc_target_info) = external {}

    # Event when a target was forgotten.
    ForgetTargetEvent<native><public>:listenable(entity) = external {}

    # Event when a target is seen. Sight sense must be active.
    SeeTargetEvent<native><public>:listenable(npc_target_info) = external {}

    # Event when a target is heard. Hearing sense must be active.
    HearTargetEvent<native><public>:listenable(npc_target_info) = external {}

    # Event when a target is touched. Touch sense must be active.
    TouchTargetEvent<native><public>:listenable(npc_target_info) = external {}

1. DetectedTargets

    # Information about all detected targets.
    var<private> DetectedTargets<native><public>:[]npc_target_info = external {}

# 検知されたすべてのターゲットに関する情報。

  • 検証結果:
    • DetectTargetEvent 発生後、DetectedTargets に追加されます
    • ForgetEvent 発生後、DetectedTargets から取り除かれます
    • 挙動の注意点: ゲーム開始時、DetectTargetEvent 発生前であってもすでにターゲットが含まれているケースがあり、初期状態のハンドリングに注意が必要です

2. DetectTargetEvent

    # Event when a target was detected.
    DetectTargetEvent<native><public>:listenable(npc_target_info) = external {}

# ターゲットが検知されたときのイベント。

動画は、DetectTargetEvent と ForgetTargetEvent を確認しています

  1. 始めは、NPCとプレイヤーは同じチームです
    検知対象が Enemies のため、プレイヤーは攻撃されません
  2. プレイヤーがボリュームに入ったとき、NPCを別チームに変更しています
    DetectTargetEvent が発生し、NPCはプレイヤーへの攻撃を開始します
  3. プレイヤーが再度ボリュームに入ったとき、NPCをプレイヤーと同じチームに戻しています
    ForgetTargetEvent が発生します
  • 検証結果:

    • 視覚、聴覚、触覚 のいずれかでターゲットを検知し、それが DetectedTargets に存在しない場合、発生します
    • 検知対象は、NPCキャラクター定義の Perception Modifier または Guard Perception Modifier 内の Detection by Affiliation 設定に依存すると考えられます
      • Detect Enemies(デフォルト)

      • Detect Neutrals

      • Detect Friendlies

        既知の不具合 (2025年12月時点)
        現在、Enemies 以外を検知対象に設定すると DetectTargetEvent が発生しない不具合が報告されています。 (公式フォーラム参照)

      デフォルトではオーバーライドしない設定で、敵のみを検知します。
      視覚(視野)、聴覚、触覚(タッチ) のそれぞれで設定できます。
      スクリーンショット 2025-12-15 231500.png

      (参考: Perception Modifier)
      Guard Perception Modifier よりも設定がシンプルそうです
      image.png

検証用コード
    # プレイヤーが Volume に入ったときに、
    # NPCの所属チームを変更する。味方なら敵に、敵なら味方チームに。
    OnVolumeEnters(Agent:agent):void=
        Print("OnVolumeEnters: ")
        if(SimE := GetSimulationEntity[]):
            NPCAwarenessComps := for(Comp : SimE.FindDescendantComponents(npc_awareness_component)){Comp}
            if(NPCAwarenessComp := NPCAwarenessComps[0]):
                if:
                    NPCAgent := GetAgentFromEntity[NPCAwarenessComp.Entity]
                    TC := GetPlayspace().GetTeamCollection()
                    TeamAttitude := TC.ToggleTeamAttitude[NPCAgent, Agent]
                then:
                    Print(" - Toggled TeamAttitude: " + ToDiagnostic(TeamAttitude))
                else:
                    Print(" - Error: Could not toggle team attitude.")

    # ターゲットを検知したときの処理。検知したターゲット情報を出力。
    OnDetectTarget(TargetInfo:npc_target_info):void=
        Print("OnDetectTarget:  " + ToDiagnostic(TargetInfo))
        Print(" - TargetInfo.Target: " + ToDiagnostic(TargetInfo.Target))
        Print(" - TargetInfo.HasLineOfSight: " + ToDiagnostic(TargetInfo.HasLineOfSight))
        Print(" - TargetInfo.Attitude: " + ToDiagnostic(TargetInfo.Attitude))
        Print(" - TargetInfo.LastKnownPosition: " + ToDiagnostic(TargetInfo.LastKnownPosition))

    # NPCに検知されている、すべてのターゲット情報を出力
    DetectedTargets_Test():void=
        Print("========== DetectedTargets_Test ==========")
        if(SimE := GetSimulationEntity[]):
            NPCAwarenessComps := for(Comp : SimE.FindDescendantComponents(npc_awareness_component)){Comp}
            if(NPCAwarenessComp := NPCAwarenessComps[0]):  
                DetectedTargets:[]npc_target_info = NPCAwarenessComp.DetectedTargets
                Print(" - DetectedTargets.Length: {DetectedTargets.Length}")
                for(I -> TargetInfo : DetectedTargets):
                    Print("   - DetectedTargets[{I}]: Target: " + ToDiagnostic(TargetInfo.Target))
                    Print("   - DetectedTargets[{I}]: HasLineOfSight: " + ToDiagnostic(TargetInfo.HasLineOfSight))
                    Print("   - DetectedTargets[{I}]: Attitude: " + ToDiagnostic(TargetInfo.Attitude))
                    Print("   - DetectedTargets[{I}]: LastKnownPosition: " + ToDiagnostic(TargetInfo.LastKnownPosition)) 

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

========== DetectedTargets_Test ==========
 - DetectedTargets.Length: 0
===============================================
OnVolumeEnters: 
 - Toggled TeamAttitude: (/Fortnite.com/Teams:)team_attitude.Hostile
OnDetectTarget:  AI_npc_target_info /VKEdit/Maps/VKEdit_EmptyOcean_VolumeSupport.VKEdit_EmptyOcean_VolumeSupport:PersistentLevel.VKEdit_EmptyOcean_VolumeSupport_SimulationEntityActor.SimulationEntity.RoundLifetimeSimulationEntity.Henchman_Prefab_Entity_C_2147482640.AI_fort_guard_perception_component_0.AI_npc_target_info_2147482638
 - TargetInfo.Target: Entity /VKEdit/Maps/VKEdit_EmptyOcean_VolumeSupport.VKEdit_EmptyOcean_VolumeSupport:PersistentLevel.VKEdit_EmptyOcean_VolumeSupport_SimulationEntityActor.SimulationEntity.RoundLifetimeSimulationEntity.PlayerPawn_Athena_C_2147482637
 - TargetInfo.HasLineOfSight: true
 - TargetInfo.Attitude: (/Fortnite.com/Teams:)team_attitude.Hostile
 - TargetInfo.LastKnownPosition: (/Verse.org/SpatialMath:)vector3{Forward := -370.63969596999425, Left := 8802.510502376554, Up := 77.15099384415615}
OnVolumeEnters: 
 - Toggled TeamAttitude: (/Fortnite.com/Teams:)team_attitude.Friendly
OnForgetTarget: TargetEntity: Entity /VKEdit/Maps/VKEdit_EmptyOcean_VolumeSupport.VKEdit_EmptyOcean_VolumeSupport:PersistentLevel.VKEdit_EmptyOcean_VolumeSupport_SimulationEntityActor.SimulationEntity.RoundLifetimeSimulationEntity.PlayerPawn_Athena_C_2147482637
OnDetectTarget:  AI_npc_target_info /VKEdit/Maps/VKEdit_EmptyOcean_VolumeSupport.VKEdit_EmptyOcean_VolumeSupport:PersistentLevel.VKEdit_EmptyOcean_VolumeSupport_SimulationEntityActor.SimulationEntity.RoundLifetimeSimulationEntity.Henchman_Prefab_Entity_C_2147482640.AI_fort_guard_perception_component_0.AI_npc_target_info_2147482637
 - TargetInfo.Target: Entity /VKEdit/Maps/VKEdit_EmptyOcean_VolumeSupport.VKEdit_EmptyOcean_VolumeSupport:PersistentLevel.VKEdit_EmptyOcean_VolumeSupport_SimulationEntityActor.SimulationEntity.RoundLifetimeSimulationEntity.PlayerPawn_Athena_C_2147482637
 - TargetInfo.HasLineOfSight: true
 - TargetInfo.Attitude: (/Fortnite.com/Teams:)team_attitude.Friendly
 - TargetInfo.LastKnownPosition: (/Verse.org/SpatialMath:)vector3{Forward := -242.2152475088556, Left := 8769.469720987045, Up := 77.14999645587599}
OnForgetTarget: TargetEntity: Entity /VKEdit/Maps/VKEdit_EmptyOcean_VolumeSupport.VKEdit_EmptyOcean_VolumeSupport:PersistentLevel.VKEdit_EmptyOcean_VolumeSupport_SimulationEntityActor.SimulationEntity.RoundLifetimeSimulationEntity.PlayerPawn_Athena_C_2147482637


3. ForgetTargetEvent

    # Event when a target was forgotten.
    ForgetTargetEvent<native><public>:listenable(entity) = external {}

# ターゲットが忘れられたときのイベント。

  • 検証結果:
    • ターゲットが忘れられたときに発生します
      DetectTargetEvent 発生以降に、以下のケースなどで発生します
      • NPCがターゲットを撃破した
      • 障害物などでターゲットを見失った
      • チーム変更により検知対象外(敵から味方へなど)になった

4. SeeTargetEvent

    # Event when a target is seen. Sight sense must be active.
    SeeTargetEvent<native><public>:listenable(npc_target_info) = external {}

# ターゲットが視認されたときのイベント。視覚センスがアクティブである必要があります。

  • 検証結果:
    • NPCキャラクター定義で設定の検知対象が見えたときに発生します
検証用コード・設定

スクリーンショット 2025-12-16 024757.png

NPCを敵チームにしてから検証開始

    OnSeeTarget(TargetInfo:npc_target_info):void=
        Print("OnSeeTarget: TargetInfo: " + ToDiagnostic(TargetInfo))
        Print(" - TargetInfo.Target: " + ToDiagnostic(TargetInfo.Target))
        Print(" - TargetInfo.HasLineOfSight: " + ToDiagnostic(TargetInfo.HasLineOfSight))
        Print(" - TargetInfo.Attitude: " + ToDiagnostic(TargetInfo.Attitude))
        Print(" - TargetInfo.LastKnownPosition: " + ToDiagnostic(TargetInfo.LastKnownPosition))

5. HearTargetEvent

    # Event when a target is heard. Hearing sense must be active.
    HearTargetEvent<native><public>:listenable(npc_target_info) = external {}

# ターゲットが聞こえたときのイベント。聴覚センスがアクティブである必要があります。

  • 検証結果:
    • NPCキャラクター定義で設定の検知対象が聞こえたときに発生します。1度発生するときは、立て続けに発生します
    • イベント発生後、必ずしもプレイヤーへの攻撃を開始しません。立っている位置から動かないことのほうが多いです
検証用コード・設定

スクリーンショット 2025-12-16 030644.png

NPCを敵チームにしてから検証開始

    # 頻繁に発生するのでログ出力は少量
    OnHearTarget(TargetInfo:npc_target_info):void=
        Print("OnHearTarget: " )

6. TouchTargetEvent

    # Event when a target is touched. Touch sense must be active.
    TouchTargetEvent<native><public>:listenable(npc_target_info) = external {}

# ターゲットに触れたときのイベント。触覚センスがアクティブである必要があります。

  • 検証結果:
    • NPCキャラクター定義で設定の検知対象に触れたとき、発生します
    • 設定の注意点: デフォルトでは検知しませんでした。NPCキャラクター定義の Override Touch Settingsオンにし、 Enable Touch を明示的に有効にすることで動作するようになります
検証用コード・設定

スクリーンショット 2025-12-16 035506.png
NPCを敵チームにしてから検証開始


    OnTouchTarget(TargetInfo:npc_target_info):void=
        Print("OnTouchTarget: called. TargetInfo: " + ToDiagnostic(TargetInfo))
        Print(" - TargetInfo.Target: " + ToDiagnostic(TargetInfo.Target))
        Print(" - TargetInfo.HasLineOfSight: " + ToDiagnostic(TargetInfo.HasLineOfSight))
        Print(" - TargetInfo.Attitude: " + ToDiagnostic(TargetInfo.Attitude))
        Print(" - TargetInfo.LastKnownPosition: " + ToDiagnostic(TargetInfo.LastKnownPosition))

おわりに

今回の検証で、NPCが「世界をどう認識しているか」をVerseで取れるようになりました。
これら知覚のイベントは、前回検証した guard_actions_component によるアクションと組み合わせることで、NPCを自在に動かすための手がかりになります。


関連記事

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?