PART 2 - 강의 3/3

병렬 실행과 Observer Aborts

Parallel, SimpleParallel 노드와 Observer Aborts 메커니즘으로 반응적 AI 행동을 구현합니다

01

SimpleParallel 노드

메인 Task와 백그라운드 서브트리 동시 실행

UBTComposite_SimpleParallel은 UE5 BT의 핵심 병렬 노드입니다. 왼쪽 자식(메인 Task)과 오른쪽 자식(백그라운드 서브트리)을 동시에 실행합니다. 메인 Task 완료 시 FinishMode에 따라 동작이 달라집니다.

C++// SimpleParallel FinishMode enum class EBTParallelMode : uint8 { // 메인 Task 완료 시 백그라운드 즉시 중단 AbortBackground, // 메인 Task 완료 후 백그라운드 완료까지 대기 WaitForBackground, }; // SimpleParallel 사용 예시 (트리 구조) // SimpleParallel [FinishMode: AbortBackground] // ├─ [Main] Task: MoveToTarget // └─ [Background] Sequence // ├─ Service: UpdateTargetLocation // ├─ Task: PlayRunAnimation // └─ Task: ShoutWarning // 핵심: SimpleParallel의 메인은 반드시 단일 Task여야 한다 // 백그라운드는 서브트리(Composite 포함) 가능 // C++ 에서 SimpleParallel 설정 UBTComposite_SimpleParallel* ParallelNode; // FinishMode 프로퍼티로 제어 ParallelNode->FinishMode = EBTParallelMode::AbortBackground;
주의

SimpleParallel의 메인 자식은 반드시 단일 Task 노드여야 합니다. Composite 노드를 메인에 배치하면 동작하지 않습니다. 복잡한 로직은 백그라운드 쪽에 배치하세요.

02

Observer Aborts 메커니즘

Decorator 조건 변경에 따른 즉각적 브랜치 전환

Observer Aborts는 UE5 BT의 핵심 반응성 메커니즘입니다. Decorator가 Blackboard 변경을 감시하다가 조건이 바뀌면, 현재 실행 중인 브랜치를 중단하고 즉시 전환합니다.

C++// FlowAbortMode 열거형 enum class EBTFlowAbortMode : uint8 { None, // Observer Aborts 비활성 LowerPriority, // 낮은 우선순위 브랜치만 중단 Self, // 자신의 브랜치만 중단 Both, // 양쪽 모두 중단 }; // 예시: Selector 아래 두 Sequence // Selector // ├─ Sequence [전투] ← 높은 우선순위 // │ ├─ Decorator: HasTarget (ObserverAborts: LowerPriority) // │ └─ Task: AttackTarget // └─ Sequence [순찰] ← 낮은 우선순위 // ├─ Task: FindPatrolPoint // └─ Task: MoveToPatrol // 시나리오 1: 순찰 중 타겟 발견 // → HasTarget Decorator가 BB "TargetActor" 변경 감지 // → LowerPriority: 순찰 브랜치(낮은 우선순위) 중단 // → 전투 브랜치로 즉시 전환 // 시나리오 2: 전투 중 타겟 상실 (Self 모드일 경우) // → HasTarget Decorator가 BB "TargetActor" = nullptr 감지 // → Self: 자신의 전투 브랜치 중단 // → Selector가 다음 브랜치(순찰) 시도
Observer Aborts 흐름
BB 값 변경 Observer 감지 조건 재평가 브랜치 중단 새 브랜치 실행

LowerPriority는 "더 중요한 일이 생기면 현재 일을 중단"하는 패턴에 사용합니다. 전투 Decorator에 LowerPriority를 설정하면, 순찰 중 적 발견 시 즉시 전투로 전환됩니다.

03

Observer Aborts 실전 패턴

Self, LowerPriority, Both의 활용 시나리오

각 FlowAbortMode는 명확한 사용 시나리오가 있습니다. 올바른 모드 선택이 반응적이면서도 안정적인 AI 행동의 핵심입니다.

C++// 패턴 1: LowerPriority - "우선순위 상승" // 적 발견 시 순찰 중단 → 전투 시작 // Selector // ├─ Sequence // │ ├─ BB Decorator: TargetActor IsSet // │ │ [Observer Aborts: LowerPriority] // │ ├─ Task: MoveToTarget // │ └─ Task: Attack // └─ Sequence // └─ Task: Patrol // 패턴 2: Self - "조건 상실 시 중단" // 타겟 사라지면 전투 중단 // Selector // ├─ Sequence // │ ├─ BB Decorator: TargetActor IsSet // │ │ [Observer Aborts: Self] // │ └─ Task: AttackTarget // └─ Task: Patrol // 패턴 3: Both - "양방향 반응" // 체력 기준으로 공격/후퇴 즉시 전환 // Selector // ├─ Sequence [공격] // │ ├─ Decorator: IsHealthAbove(0.3) // │ │ [Observer Aborts: Both] // │ └─ Task: AggressiveAttack // └─ Sequence [후퇴] // └─ Task: Retreat // 패턴 4: Cooldown + Observer Aborts 조합 // 스킬 사용 후 쿨다운 동안 다른 행동 // Selector // ├─ Sequence [스킬] // │ ├─ Decorator: Cooldown(5.0) // │ ├─ Decorator: IsInRange // │ │ [Observer Aborts: LowerPriority] // │ └─ Task: UseSpecialSkill // └─ Sequence [기본 공격] // └─ Task: BasicAttack
주의

Both 모드는 양방향으로 중단이 발생하므로, 두 브랜치가 빠르게 번갈아 전환되는 "핑퐁 현상"이 발생할 수 있습니다. Cooldown Decorator를 함께 사용하여 방지하세요.

04

Conditional Abort의 내부 동작

Request Execution과 Search 프로세스

Observer Aborts가 트리거되면 RequestExecution()이 호출되어 현재 활성 노드를 중단하고 새로운 Search를 시작합니다. 이 과정에서 AbortTask()가 호출되므로, 정리 로직이 필수입니다.

C++// Observer Aborts 내부 처리 흐름 (개념) void UBTDecorator::ConditionalFlowAbort( UBehaviorTreeComponent& OwnerComp) const { // 1. 조건 재평가 bool bNewCondition = CalculateRawConditionValue(OwnerComp, ...); // 2. FlowAbortMode에 따라 중단 대상 결정 if (FlowAbortMode == EBTFlowAbortMode::LowerPriority) { // 현재 실행 중인 노드가 낮은 우선순위 브랜치에 있으면 // → 중단 요청 OwnerComp.RequestExecution(this); } else if (FlowAbortMode == EBTFlowAbortMode::Self) { // 자신의 브랜치가 활성 상태이고 조건이 거짓이면 // → 자신의 브랜치 중단 OwnerComp.RequestExecution(this); } } // RequestExecution 처리 // 1. 현재 활성 Task의 AbortTask() 호출 // 2. 활성 브랜치의 Service들 OnCeaseRelevant() 호출 // 3. 새로운 Search 시작 - 다음 실행할 Task 탐색 // 4. 새 브랜치의 Service들 OnBecomeRelevant() 호출 // 5. 새 Task의 ExecuteTask() 호출 // 디버깅: BT 에디터에서 Observer Aborts 시각화 // - LowerPriority: 파란색 하단 바 // - Self: 빨간색 하단 바 // - Both: 파란색 + 빨간색 하단 바

BT 에디터에서 노드 하단의 색상 바로 Observer Aborts 모드를 확인할 수 있습니다. 파란색은 LowerPriority, 빨간색은 Self를 나타냅니다.

SUMMARY

핵심 요약

  • SimpleParallel은 메인 Task와 백그라운드 서브트리를 동시 실행하며, FinishMode로 완료 시 동작을 제어한다
  • Observer Aborts는 Decorator가 BB 변경을 감시하여 조건 변화 시 즉각적 브랜치 전환을 가능하게 한다
  • LowerPriority는 우선순위 상승, Self는 조건 상실 중단, Both는 양방향 반응에 사용한다
  • Both 모드 사용 시 핑퐁 현상에 주의하고, Cooldown Decorator로 방지해야 한다
PRACTICE

도전 과제

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

실습 1: Simple Parallel 실습

Simple Parallel 노드를 사용하여 '이동하면서 총 쏘기' 행동을 구현하세요. Main Task에 이동, Background에 공격을 배치하고 동시 실행을 확인합니다.

실습 2: Observer Aborts 설정

Decorator에 Observer Aborts를 Self, Lower Priority, Both로 각각 설정하고 행동 차이를 관찰하세요. '적 감지 시 순찰 중단하고 전투 전환'을 Observer Aborts로 구현합니다.

심화 과제

BTTask에서 RunBehaviorTreeDynamic()을 호출하여 런타임에 서브트리를 교체하는 시스템을 구현하세요. 보스 AI의 페이즈별 행동 패턴 전환에 활용합니다.