PART 2 - 강의 1/3

BT 노드 타입과 실행 흐름

Composite, Task, Decorator, Service 노드의 역할과 Behavior Tree 실행 순서를 깊이 이해합니다

01

Behavior Tree 노드 계층 구조

UBTNode를 루트로 하는 노드 타입 체계

UE5의 Behavior Tree는 UBTNode를 최상위 클래스로 하여 크게 4가지 노드 타입으로 구성됩니다. 각 노드는 고유한 역할을 가지며, 이들의 조합으로 복잡한 AI 행동을 구현합니다.

BT 노드 계층
UBTNode (Base) UBTCompositeNode UBTTaskNode UBTAuxiliaryNode
C++// UE5 BT 노드 클래스 계층 // UBTNode // ├── UBTCompositeNode (Selector, Sequence, SimpleParallel) // ├── UBTTaskNode (MoveTo, Wait, RunEQSQuery, ...) // └── UBTAuxiliaryNode // ├── UBTDecorator (Blackboard, ConeCheck, Cooldown, ...) // └── UBTService (DefaultFocus, RunEQS, ...) // Composite 노드 - 자식 노드의 실행 순서를 결정 class AIMODULE_API UBTCompositeNode : public UBTNode { // Children: 자식 노드 배열 // 각 자식은 FBTCompositeChild 구조체로 래핑 TArray<FBTCompositeChild> Children; }; // Task 노드 - 실제 행동을 수행 class AIMODULE_API UBTTaskNode : public UBTNode { // ExecuteTask(): 행동 실행 진입점 // AbortTask(): 중단 시 호출 }; // Auxiliary 노드 - Decorator/Service의 베이스 class AIMODULE_API UBTAuxiliaryNode : public UBTNode { // 자체적으로 실행되지 않고, 부착된 노드를 보조 };
구조

Composite 노드는 "흐름 제어", Task 노드는 "행동 실행", Decorator는 "조건 검사", Service는 "주기적 작업"이라는 명확한 역할 분담을 가집니다.

02

Composite 노드: Selector와 Sequence

자식 노드의 실행 순서와 성공/실패 전파 규칙

Selector는 자식 중 하나가 성공하면 즉시 성공을 반환하고(OR 논리), Sequence는 모든 자식이 성공해야 성공을 반환합니다(AND 논리). 이 두 Composite가 BT의 흐름 제어 핵심입니다.

C++// Selector: 자식을 왼쪽부터 실행, 하나라도 성공하면 Success // - 자식이 Succeeded 반환 → Selector도 Succeeded // - 자식이 Failed 반환 → 다음 자식 시도 // - 모든 자식 Failed → Selector도 Failed // Sequence: 자식을 왼쪽부터 실행, 모두 성공해야 Success // - 자식이 Succeeded 반환 → 다음 자식 실행 // - 자식이 Failed 반환 → Sequence도 Failed // - 모든 자식 Succeeded → Sequence도 Succeeded // 실행 결과 열거형 enum class EBTNodeResult : uint8 { Succeeded, // 성공 Failed, // 실패 Aborted, // 중단됨 InProgress, // 아직 진행 중 (비동기 Task) }; // BT 실행 예시 구조 // Root // └─ Selector // ├─ Sequence [전투] // │ ├─ Decorator: HasTarget? // │ ├─ Task: MoveToTarget // │ └─ Task: Attack // └─ Sequence [순찰] // ├─ Task: FindPatrolPoint // └─ Task: MoveToPatrol

Selector는 "우선순위 선택"에 사용합니다. 왼쪽 자식이 높은 우선순위입니다. 전투 > 추적 > 순찰 순서로 배치하면, 전투 조건이 실패하면 자동으로 다음 행동을 시도합니다.

03

Task 노드와 실행 결과

실제 행동을 수행하는 리프 노드

Task 노드는 BT의 리프(leaf)에 위치하며, 실제 AI 행동을 수행합니다. UE5는 다양한 빌트인 Task를 제공하고, C++이나 블루프린트로 커스텀 Task를 만들 수 있습니다.

C++// 주요 빌트인 Task 노드 // UBTTask_MoveTo - 지정 위치/액터로 이동 // UBTTask_Wait - 지정 시간 대기 // UBTTask_WaitBlackboardTime - BB 값만큼 대기 // UBTTask_RunEQSQuery - EQS 쿼리 실행 // UBTTask_PlayAnimation - 애니메이션 재생 // UBTTask_MakeNoise - 소음 발생 (Perception 연동) // UBTTask_RotateToFaceBBEntry - BB 대상을 향해 회전 // UBTTask_GameplayTaskBase - GameplayTask 연동 // Task 실행 흐름 class UBTTask_MoveTo : public UBTTask_BlackboardBase { virtual EBTNodeResult::Type ExecuteTask( UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override { // 이동 요청 시작 // InProgress 반환 → 이동 완료 시 FinishLatentTask() 호출 return EBTNodeResult::InProgress; } // 비동기 완료 시 호출 void OnMoveCompleted(FAIRequestID RequestID, EPathFollowingResult::Type Result) { FinishLatentTask(OwnerComp, Result == EPathFollowingResult::Success ? EBTNodeResult::Succeeded : EBTNodeResult::Failed); } };
주의

InProgress를 반환한 Task는 반드시 나중에 FinishLatentTask()를 호출해야 합니다. 호출하지 않으면 BT가 해당 노드에서 영원히 멈춥니다.

04

Decorator와 Service

조건 검사와 주기적 업데이트를 담당하는 보조 노드

Decorator는 Composite나 Task에 부착되어 실행 조건을 검사합니다. Service는 Composite에 부착되어 해당 브랜치가 활성 상태인 동안 주기적으로 실행됩니다.

C++// 주요 빌트인 Decorator // UBTDecorator_Blackboard - BB Key 조건 검사 // UBTDecorator_CheckGameplayTagsOnActor - 게임플레이 태그 확인 // UBTDecorator_ConeCheck - 시야각 내 존재 확인 // UBTDecorator_Cooldown - 쿨다운 타이머 // UBTDecorator_DoesPathExist - 경로 존재 여부 // UBTDecorator_ForceSuccess - 항상 성공으로 변환 // UBTDecorator_IsAtLocation - 위치 도달 확인 // UBTDecorator_Loop - 반복 실행 // UBTDecorator_TimeLimit - 시간 제한 // Decorator 핵심 메서드 class UBTDecorator : public UBTAuxiliaryNode { // 조건 검사 - true면 실행 허용 virtual bool CalculateRawConditionValue( UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const; // Observer Aborts 설정 EBTFlowAbortMode::Type FlowAbortMode; }; // 주요 빌트인 Service // UBTService_BlackboardBase - BB 값 업데이트 // UBTService_DefaultFocus - AI Focus 대상 설정 // UBTService_RunEQS - 주기적 EQS 실행 // Service 핵심 메서드 class UBTService : public UBTAuxiliaryNode { // 주기적 호출 (Interval 간격) virtual void TickNode( UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds); float Interval; // 기본 호출 간격 float RandomDeviation; // 랜덤 편차 };

Service의 Interval에 RandomDeviation을 설정하면 여러 AI가 동시에 Service를 실행하는 것을 분산시켜 프레임 스파이크를 방지할 수 있습니다.

05

BT 실행 흐름과 Search 알고리즘

BehaviorTreeComponent의 실행 사이클

UE5의 BT는 이벤트 기반 실행 모델을 사용합니다. 매 프레임 전체 트리를 순회하지 않고, 활성 노드와 관련 Service만 Tick합니다. 노드 전환은 Search 과정을 통해 다음 실행할 Task를 결정합니다.

BT 실행 사이클
Search (다음 노드 탐색) Decorator 평가 Task 실행 Service Tick 결과 전파
C++// BehaviorTreeComponent의 핵심 실행 로직 (개념) void UBehaviorTreeComponent::ProcessExecutionRequest() { // 1. 현재 Task가 완료되었으면 Search 시작 // 2. Search: 부모 Composite에게 다음 자식 요청 // 3. 다음 자식의 Decorator 조건 평가 // 4. 조건 통과 시 해당 Task 실행 // 5. 활성 브랜치의 Service들은 계속 Tick } // 노드 메모리 시스템 // 각 BT 인스턴스마다 독립적인 메모리 공간 할당 struct FBTNodeMemory { // 노드별 런타임 상태 저장 // 예: MoveTo의 이동 상태, Wait의 남은 시간 등 }; // 디버그: BT 실행 상태 확인 // 에디터 → AI → Behavior Tree 디버거 // 또는 런타임에 GameplayDebugger (') 활용
핵심

UE5 BT의 이벤트 기반 모델은 전통적인 매 프레임 트리 순회 방식보다 훨씬 효율적입니다. Observer Aborts와 결합하면, 조건 변경 시 즉각적으로 브랜치를 전환할 수 있습니다.

SUMMARY

핵심 요약

  • Composite 노드(Selector/Sequence)가 자식 실행 순서를 결정하며, Selector는 OR, Sequence는 AND 논리를 따른다
  • Task 노드는 실제 행동을 수행하는 리프 노드이며, InProgress 반환 시 반드시 FinishLatentTask()를 호출해야 한다
  • Decorator는 실행 조건을, Service는 주기적 업데이트를 담당하는 보조 노드이다
  • UE5 BT는 이벤트 기반 실행 모델로, 매 프레임 전체 트리를 순회하지 않아 효율적이다
PRACTICE

도전 과제

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

실습 1: BT 실행 흐름 관찰

간단한 BT(Sequence -> MoveTo -> Wait -> Sequence 반복)를 만들고 BT 에디터의 디버깅 모드에서 실행 흐름을 관찰하세요. 각 노드의 InProgress/Success/Failure 상태 전이를 추적합니다.

실습 2: Selector vs Sequence 비교

동일한 AI 행동을 Selector와 Sequence로 각각 구현하세요. 자식 노드의 Success/Failure에 따른 분기 차이를 BT 디버거에서 확인하고, 적절한 사용 시나리오를 정리합니다.

심화 과제

순찰 -> 적 발견 시 추적 -> 사거리 내 도달 시 공격 -> 적 상실 시 마지막 위치 수색 -> 순찰 복귀의 전체 AI 루프를 BT로 구현하세요.