PART 4 · 강의 2/3

StateTree 통합

Mass Entity에서 StateTree를 활용한 AI 행동 결정 시스템을 구현합니다

01

StateTree 기본 개념

Behavior Tree를 대체하는 새로운 AI 행동 모델링 시스템

StateTree는 UE5에서 Behavior Tree의 대안으로 도입된 계층적 상태 머신입니다. Mass Entity와의 통합이 기본 설계에 포함되어 있어 대규모 AI에 최적화되어 있습니다.

StateTree vs Behavior Tree

StateTree는 상태 기반(현재 상태에서 조건에 따라 전환)이고, Behavior Tree는 태스크 기반(루트에서 매 틱 평가)입니다. Mass Entity에서는 StateTree만 지원됩니다.

StateTree 구조 예시 // Mass Entity용 StateTree 구조 // // Root // ├── State: Idle // │ └── Task: MassWaitTask (대기) // │ └── Transition → Patrol (타이머 만료) // │ // ├── State: Patrol // │ └── Task: MassFindSmartObjectTask (경로 탐색) // │ └── Task: MassMoveToTask (이동) // │ └── Transition → Idle (도착) // │ └── Transition → Alert (적 감지) // │ // ├── State: Alert // │ └── Task: MassLookAtTask (적 주시) // │ └── Transition → Chase (적 근접) // │ └── Transition → Patrol (적 소실) // │ // └── State: Chase // └── Task: MassMoveToTask (적 추적) // └── Transition → Alert (적 멀어짐)
02

Mass StateTree 서브시스템

StateTree를 Mass Entity와 연결하는 서브시스템

UMassStateTreeSubsystem이 모든 엔티티의 StateTree 인스턴스를 관리합니다. 각 엔티티의 StateTree를 업데이트하고, Signal에 반응하여 상태를 전환합니다.

C++ - StateTree Trait 설정 // MassEntityConfig에 StateTree Trait 추가 // ┌─────────────────────────────────────┐ // │ DA_SmartCivilian Config │ // │ │ // │ Traits: │ // │ [0] UMassStateTreeTrait │ // │ StateTree: ST_CivilianBehavior │ // │ [1] UMassMovementTrait │ // │ [2] UMassNavigationTrait │ // │ [3] UMassVisualizationTrait │ // └─────────────────────────────────────┘ // StateTree Trait가 추가하는 Fragment들: // - FMassStateTreeInstanceFragment (StateTree 인스턴스 데이터) // - StateTree에서 사용하는 추가 Fragment들

StateTree 핵심 원칙

데이터 설정만, 실행은 하지 않음

Mass StateTree의 Task는 직접 이동을 실행하거나 위치를 변경하지 않습니다. 대신 Fragment에 데이터를 설정합니다. 예: MoveTarget Fragment에 목표 위치를 설정하면, Movement Processor가 실제 이동을 수행합니다. 이것이 ECS의 데이터/로직 분리 원칙입니다.

03

Mass StateTree Task

Mass Entity 전용 StateTree Task 작성법

C++ - 커스텀 Mass StateTree Task // Mass Entity용 StateTree Task USTRUCT() struct FMassSetRandomTargetTask : public FMassStateTreeTaskBase { GENERATED_BODY() // Task에서 접근할 데이터 핸들 UPROPERTY(EditAnywhere, Category = "Context") FStateTreeExternalDataHandle MoveTargetHandle; UPROPERTY(EditAnywhere, Category = "Context") FStateTreeExternalDataHandle TransformHandle; UPROPERTY(EditAnywhere, Category = "Parameter") float WanderRadius = 2000.0f; // Task 진입 시 호출 virtual EStateTreeRunStatus EnterState( FStateTreeExecutionContext& Context, const FStateTreeTransitionResult& Transition) const override { // Fragment 데이터 접근 FMassMoveTargetFragment& MoveTarget = Context.GetExternalData(MoveTargetHandle); const FTransformFragment& Transform = Context.GetExternalData(TransformHandle); // 현재 위치에서 랜덤한 방향으로 목표 설정 FVector CurrentPos = Transform.Transform.GetLocation(); FVector RandomDir = FMath::VRand(); RandomDir.Z = 0.0f; RandomDir.Normalize(); MoveTarget.Center = CurrentPos + RandomDir * FMath::RandRange( WanderRadius * 0.5f, WanderRadius); MoveTarget.DesiredSpeed.Set(200.0f); MoveTarget.IntentAtGoal = EMassMovementAction::Stand; return EStateTreeRunStatus::Running; } // 매 틱 호출 (도착 체크 등) virtual EStateTreeRunStatus Tick( FStateTreeExecutionContext& Context, const float DeltaTime) const override { const FMassMoveTargetFragment& MoveTarget = Context.GetExternalData(MoveTargetHandle); // 도착했으면 완료 if (MoveTarget.GetCurrentAction() == EMassMovementAction::Stand) { return EStateTreeRunStatus::Succeeded; } return EStateTreeRunStatus::Running; } };
04

Signal과 StateTree 전환

외부 이벤트로 StateTree 상태 전환을 트리거하는 방법

C++ - Signal로 StateTree 재평가 트리거 // Processor에서 Signal 전송 void UAlertProcessor::Execute( FMassEntityManager& EntityManager, FMassExecutionContext& Context) { AlertQuery.ForEachEntityChunk(EntityManager, Context, [](FMassExecutionContext& Ctx) { UMassSignalSubsystem& Signals = Ctx.GetMutableSubsystemChecked<UMassSignalSubsystem>(); auto Entities = Ctx.GetEntities(); for (int32 i = 0; i < Ctx.GetNumEntities(); ++i) { // 근처에 적이 감지되면 시그널 전송 if (IsEnemyNearby(Ctx, i)) { Signals.SignalEntity( TEXT("EnemyDetected"), Entities[i]); } } }); } // StateTree에서 Signal을 Transition 조건으로 사용: // State: Patrol // Transition: // Trigger: MassSignal("EnemyDetected") // Target State: Alert
Signal의 장점

Signal은 StateTree의 빈번한 재평가를 방지합니다. 매 틱마다 조건을 체크하는 대신, 변화가 발생했을 때만 Signal을 보내 재평가를 트리거합니다. 수만 개의 AI에서 이 차이는 성능에 큰 영향을 줍니다.

SUMMARY

핵심 요약

  • StateTree는 Mass Entity의 AI 행동 결정 시스템으로, 계층적 상태 머신 기반이다
  • UMassStateTreeSubsystem이 모든 엔티티의 StateTree 인스턴스를 관리한다
  • StateTree Task는 Fragment에 데이터만 설정하고, 실제 실행은 Processor가 담당한다
  • FMassStateTreeTaskBase를 상속하여 커스텀 Mass 전용 Task를 작성한다
  • MassSignal로 StateTree의 상태 전환을 트리거하여 불필요한 재평가를 방지한다
  • MassEntityConfig에 UMassStateTreeTrait를 추가하여 StateTree를 엔티티에 연결한다
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: 기본 StateTree 에셋 생성

StateTree 에디터에서 Mass Entity용 StateTree를 생성하세요. Idle -> Wander -> Return 상태를 만들고, 각 상태에 Mass 전용 Task(MassMoveToTarget 등)를 할당하세요.

실습 2: StateTree 조건 분기 구현

StateTree에 조건(Distance to Target, Health Threshold 등)을 추가하여 Mass Entity가 상황에 따라 다른 행동을 선택하도록 하세요. 적이 가까우면 Flee, 멀면 Patrol 등의 분기를 만드세요.

심화 과제: 커스텀 StateTree Task 작성

FMassStateTreeTaskBase를 상속받아 커스텀 Task를 작성하세요. 예: 주변 N미터 내의 아군 엔티티를 찾아 그쪽으로 이동하는 GroupUp Task를 만들고 StateTree에 등록하세요.