콘텐츠로 이동

UE5 State Tree — 계층적 AI 상태 머신

State Tree는 UE5 5.1에서 도입된 계층적 유한 상태 머신(HFSM) 에셋 기반 시스템입니다. 기존 Behavior Tree가 태스크 순서 실행에 최적화된 반면, State Tree는 상태 전환 로직과 데이터 바인딩을 에디터에서 시각적으로 구성할 수 있습니다. Mass Entity와도 통합됩니다.


Edit → Plugins → AI → StateTree → Enable
Edit → Plugins → Gameplay → GameplayStateTree → Enable

StateTree 에셋
├── Parameters (외부 입력값)
├── Evaluators (매 틱 상태 평가)
│ └── EnemyPerceptionEvaluator
└── Root State
├── Patrol State
│ ├── Enter Tasks
│ ├── State Tasks
│ │ └── PatrolTask
│ └── Transitions
│ └── [PlayerDetected] → Chase State
├── Chase State
│ ├── State Tasks
│ │ └── ChaseTask
│ └── Transitions
│ └── [PlayerLost] → Patrol State
└── Attack State

// Evaluator: 매 틱 실행, 공유 데이터 업데이트
USTRUCT()
struct FEnemyPerceptionEvaluator : public FStateTreeEvaluatorBase
{
GENERATED_BODY()
// 출력 데이터 (다른 Task에서 참조)
UPROPERTY(EditAnywhere)
FStateTreePropertyRef<bool> bPlayerDetected;
UPROPERTY(EditAnywhere)
FStateTreePropertyRef<FVector> PlayerLocation;
using FInstanceDataType = FEnemyPerceptionEvaluatorInstanceData;
virtual void Tick(FStateTreeExecutionContext& Context,
const float DeltaTime) const override
{
auto& [bDetected, Location] = Context.GetInstanceData(*this);
// AI Perception에서 감지 결과 읽기
auto* PerceptionComp = Context.GetOwner<AAIController>()
->GetComponent<UAIPerceptionComponent>();
TArray<AActor*> Perceived;
PerceptionComp->GetCurrentlyPerceivedActors(
UAISense_Sight::StaticClass(), Perceived);
bDetected = !Perceived.IsEmpty();
if (bDetected)
Location = Perceived[0]->GetActorLocation();
}
};

// Task: 상태 진입/틱/탈출 처리
USTRUCT()
struct FChaseTask : public FStateTreeTaskBase
{
GENERATED_BODY()
// 입력 바인딩 (Evaluator 출력 연결)
UPROPERTY(EditAnywhere)
FStateTreePropertyRef<FVector> TargetLocation;
using FInstanceDataType = FChaseTaskInstanceData;
virtual EStateTreeRunStatus EnterState(
FStateTreeExecutionContext& Context,
const FStateTreeTransitionResult& Transition) const override
{
// 추적 시작
return EStateTreeRunStatus::Running;
}
virtual EStateTreeRunStatus Tick(
FStateTreeExecutionContext& Context,
const float DeltaTime) const override
{
auto& [Target] = Context.GetInstanceData(*this);
auto* AIController = Context.GetOwner<AAIController>();
UAIBlueprintHelperLibrary::SimpleMoveToLocation(
AIController, Target);
// 도착 여부 확인
float Distance = FVector::Dist(
AIController->GetPawn()->GetActorLocation(), Target);
return Distance < 100.0f
? EStateTreeRunStatus::Succeeded
: EStateTreeRunStatus::Running;
}
virtual void ExitState(
FStateTreeExecutionContext& Context,
const FStateTreeTransitionResult& Transition) const override
{
// 이동 중지
Context.GetOwner<AAIController>()->StopMovement();
}
};

UCLASS()
class AEnemyAIController : public AAIController
{
GENERATED_BODY()
UPROPERTY(EditAnywhere)
UStateTree* EnemyStateTree;
UPROPERTY(VisibleAnywhere)
UStateTreeComponent* StateTreeComponent;
public:
AEnemyAIController()
{
StateTreeComponent = CreateDefaultSubobject<UStateTreeComponent>(
TEXT("StateTree"));
}
virtual void OnPossess(APawn* InPawn) override
{
Super::OnPossess(InPawn);
StateTreeComponent->StartLogic();
}
virtual void OnUnPossess() override
{
StateTreeComponent->StopLogic("Unpossessed");
Super::OnUnPossess();
}
};

에디터에서 Transition 설정:

Trigger: On State Task Succeeded / On State Task Failed / On Tick
Condition:
- bPlayerDetected == true → Chase State
- Health < 0.2f → Flee State

항목Behavior TreeState Tree
구조태스크 트리계층 상태 머신
전환 조건데코레이터Transition + Condition
데이터 공유Blackboard구조체 바인딩
Mass 통합제한적완전 지원
에디터 지원성숙UE5 5.1+

State Tree는 상태 전환이 명확한 AI(순찰→추격→공격→후퇴)에서 Behavior Tree보다 직관적인 구조를 제공합니다. Evaluator로 매 틱 상태를 평가하고 Task로 행동을 구현하며, 에디터의 데이터 바인딩으로 코드 없이 조건을 연결하는 것이 핵심 패턴입니다.