언어:

언리얼 엔진 4 비헤이비어 트리가 다른 점

이 글은 일반적인 비헤이비어 트리에 익숙하면서 언리얼 엔진 4 의 구현에 가급적 빠르게 익숙해지고자 하는 분들을 위한 글입니다. 전에 비헤이비어 트리를 사용해 본 적이 없는 분들은, 여기 있는 설명이 약간 헛갈릴 수도 있습니다.

비헤이비어 트리의 UE4 구현이 "표준" 비헤이비어 트리와 핵심적으로 다른 점이 세 가지 있습니다:

UE4 비헤이비어 트리는 이벤트 주도형

이벤트 주도형 비헤이비어 트리는 모든 프레임마다 많은 작업을 하지는 않습니다. 관련된 변화가 일어났나 지속적으로 확인하는 대신, 비헤이비어 트리는 트리 내 변화를 발동시킬 수 있는 "이벤트"를 그냥 수동적으로 기다립니다.

이벤트 주도형 아키텍처를 통해 퍼포먼스와 디버깅 양쪽 측면이 개선되었습니다. 하지만 이러한 개선사항을 최대한 활용하기 위해서는, 우리 트리에 대한 다른 차이점을 이해하고, 비헤이비어 트리를 적절히 짤 필요가 있습니다.

퍼포먼스 개선 - 코드가 매 틱마다 전체 트리를 대상으로 반복처리할 필요가 없기 때문에, 퍼포먼스가 훨씬 뛰어납니다! 개념적으로는, "도착 했는가" 하고 계속해서 묻기 보다는, 그냥 도착할 때까지 쉬고 있다가 "도착했어!" 하는 것입니다.

디버깅 개선 - 비헤이비어 트리의 실행 히스토리를 한 단계씩 앞뒤로 이동하면서 비헤이비어를 시각적으로 디버깅할 때, 히스토리가 연관성이 있는 변화만 표시하고 무관한 것들은 표시하지 않도록 하는 것이 이상적입니다. 이벤트 주도형 구현에서는, 트리를 대상으로 반복처리하여 전과 같은 비헤이비어를 선택한 무관한 단계를 걸러낼 필요가 없습니다. 왜냐면 그러한 부가적인 반복처리가 애초에 일어난 적이 없기 때문입니다! 대신, 트리 내 실행 위치나 블랙보드 값의 변경만이 중요하며, 그러한 차이점만 표시하는 것은 쉽습니다.

조건문이 리프 노드가 아님

비헤이비어 트리 표준 모델에서, 조건문은 "태스크" 리프 노드로, 성공 또는 실패 이외 그저 아무것도 하지 않습니다. 물론 전통적인 조건문 태스크를 만들지 못할 이유는 없지만, 조건문에는 우리 데코레이터 시스템을 사용할 것을 강력 추천합니다.

조건문을 태스크가 아닌 데코레이터로 만드는 것은 몇 가지 엄청난 장점이 있습니다.

우선, 조건문 데코레이터는 비헤이비어 트리 UI 를 보다 직관적이고 읽기 쉽게 만들어 줍니다. 조건문은 자신이 제어하는 서브 트리의 루트에 있기 때문에, 조건이 충족되지 않은 경우 트리 어느 부분이 "닫혔는지" 바로 알 수 있습니다. 또한, 모든 리프가 액션 태스크이기 때문에, 트리를 통해 실제 어떤 액션이 내려졌는지 알기가 더욱 쉽습니다. 전통적인 모델에서 조건문은 리프 사이에 있어서, 어느 리프가 조건문이고 어느 것이 액션인지 알아내는 데 시간이 더 걸렸었습니다.

decorator.png

비헤이비어 트리 이 섹션에서는, Close EnoughBlackboard 데코레이터가 시퀀스 노드의 자손 실행을 막을 수 있습니다.

조건문 데코레이터의 또다른 장점은, 그 데코레이터를 트리 내 중요 노드에서 (이벤트를 기다리는) 관찰자 역할을 하도록 만드는 것이 쉽다는 것입니다. 이 기능은 트리의 이벤트 주도형 속성 장점을 최대한 이끌어내는 데 있어 매우 중요합니다.

동시발생 비헤이비어에 대한 특수 처리

"표준" 비헤이비어 트리는 종종 "Parallel" (병렬) 컴포짓 노드로 동시발생 비헤이비어를 처리합니다. 병렬 노드는 그 모든 자손의 실행을 동시에 시작시킵니다. 특수한 규칙을 통해 그 자손 트리 중 하나 이상이 끝났을 때 (원하는 비헤이비어에 따라) 어떻게 대할 것인지 결정합니다.

병렬 노드가 반드시 멀티 스레딩(태스크를 "정말" 동시에 실행시키는 것)일 필요는 없습니다. 그냥 한 번에 여러가지 태스크를 수행하는 개념적 방식 중 하나일 뿐입니다. 아직도 같은 스레드에 실행되어 어떤 시퀀스로 시작되기도 합니다. 그 시퀀스는 모두 같은 프레임에 발생하기에 무관할 것이지만, 여전히 가끔은 중요하기도 합니다.

복잡한 "병렬" 노드 대신, UE4 비헤이비어 트리는 "단순 병렬" 노드와 "서비스" 라는 독자적인 특수 노드 유형을 사용하여 거의 비슷한 비헤이비어를 이뤄내고 있습니다.

"병렬" 노드를 사용하지 않는 이유

  1. 병렬 노드는 비교적 단순한 비헤이비어도 매우 헛갈릴 수 있습니다.

    실제로 병렬 노드는 별도의 서브 트리를 한꺼번에 동시 실행시키는데, 그 중 하나가 실패하면 서브 트리 전부 또는 일부를 중단시켜야 할 수 있습니다. 아니면 나머지가 (성공이든 실패든) 완료되면 "성공"이 될 수도 있습니다. 또는... 기타등등! 병렬 비헤이비어는 단순한 경우에도 헛갈릴 수가 있으며, 잠재적으로 가능한 옵션 수에 따라 더욱 더 헛갈리게 될 수가 있습니다.

  2. 병렬 노드는 퍼포먼스 최적화가 힘들어집니다. 특히나 이벤트 주도형 트리 제작에는 더합니다.

"병렬" 노드 대신 UE4 에서 사용하는 것

보통 병렬 노드를 통해 얻을 수 있는 기능을 제공하는 노드는 세 가지 유형이 있습니다:

"단순 병렬" 노드

단순 병렬 노드는 자손을 딱 둘만 허용합니다: 하나는 (옵션으로 데코레이터가 딸린) 단일 태스크 노드여야 하고, 나머지는 완결된 서브트리여야 합니다.

단순 병렬 노드는 "A 를 하는 도중 B 도 해라" 라고 생각해 볼 수 있습니다. 예를 들어 "적을 공격하는 도중에는, 적을 향해 움직여라." 하는 것입니다. 기본적으로 A 는 주요 태스크이고, B 는 A 가 완료되기까지 기다리는 도중의 부차적 또는 필터링 태스크입니다.

부차적인 "사이" (B) 태스크 처리 관련 몇 가지 옵션이 있는 반면, 노드는 전통적 병렬 노드에 비할 때 개념적으로 비교적 단순합니다. 그렇다고는 해도, 흔히 병렬 노드가 사용되는 경우를 다수 지원합니다.

단순 병렬 노드 덕에 이벤트 주도형 최적화가 쉽게 가능했습니다. 최대 병렬 노드는 최적화에 훨씬 복잡했을 것입니다.

서비스

서비스는 (선택기, 시퀀스, 단순 병렬) 컴포짓 노드와 연관된 특수 노드로, X 초마다 콜백 등록한 다음 주기적으로 발생시킬 필요가 있는 다양한 유형의 업데이트를 수행합니다.

예를 들어 AI 폰이 현재 적을 쫓아가는 비헤이비어 트리를 정상적으로 따라가는 와중에 어느 적이 최적의 대상인지 결정하는 데 서비스를 사용할 수 있습니다.

서비스는 거기에 관련이 있는 컴포짓 노드에 루트를 둔 서브트리에 실행이 머물러 있는 동안만 활성화됩니다.

데코레이터 "Observer Aborts" 프로퍼티

표준 병렬 노드가 자주 쓰이는 경우 한 가지는, 조건을 지속적으로 검사하여 요구 조건이 false 가 되는 경우 태스크를 중단시키는 것입니다. 예를 들어, "꼬리 흔들기" 와 "덮치기" 시퀀스를 수행하는 고양이가 있는 경우, 쥐가 쥐구멍으로 탈출한 순간 즉시 포기하도록 하는 것이 좋을 것입니다. "병렬" 노드로는 쥐를 덮칠 수 있는지 검사하도록 하는 자손 하나에, 수행할 시퀀스를 또다른 자손에 넣어둘 것입니다. 우리 비헤이비어 트리는 이벤트 주도형이므로 이것을 어떻게 처리하냐면, 조건문 데코레이터에게 그 값을 "관찰"시키다가 필요한 때 중단시키도록 합니다. (이 예제에서는 시퀀스 자체에 "쥐를 덮칠 수 있는가?" 데코레이터를 두고, "관찰자 중단" 은 "자신" 으로 설정해 두었습니다. )

동시발생 비헤이비어에 대한 UE4 접근법의 장점

명확성

서비스와 단순 병렬 노드로 이해하기 쉬운 단순한 트리를 만듭니다.

디버깅 편의

명확한 그래프가 디버깅도 쉽습니다. 추가로, "동시" 실행 경로가 적다는 것은 그래프에서 실제로 무엇이 벌어지는지 알아보는 데 있어 엄청난 이점입니다.

쉬운 최적화

이벤트 주도형 그래프는 "동시" 실행 서브트리가 많지 않다면 최적화가 더욱 쉽습니다.

자주 묻는 질문

"정말 병렬 노드로 할 수 있는 것은 무엇이든 할 수 있나요?"

  • 저희가 제공하는 노드만 가지고도 필요한 모든 작업을, 더 나은 인터페이스로 하실 수 있다고 믿습니다! 위의 노드로 대부분의 경우를 처리할 수 있는 것은 확실합니다. 처리가 불가능하거나 바람직하지 못한 희귀 경우가 생긴다면, 그 처리를 위해 픽스 추가를 고려할 것입니다.

"UE4 비헤이비어 트리와 "표준" 비헤이비어 트리 차이점이 이게 전부인가요?"

  • "표준"을 따옴표로 묶은 것은 다 이유가 있습니다. ;) 사실 "표준" 이란 것은 없거든요. 그래서 UE4 구현과 여러분이 가장 익숙한 구현 사이에는 차이점이 얼마든지 있을 수 있습니다. 특이한 구현에 익숙하신 경우라면 중대한 차이점이 더 있을 수도 있으며, 그와는 무관하게 좀 더 미묘한 차이점도 있을 수 있습니다. 그저 이 글을 통해 여러분이 트리를 작성하는 데 있어 가장 중요한 차이점을 파악하는 데 도움이 되었으면 하는 바람입니다. 저희 특수 노드 유형 관련 상세 정보는, 그에 관련된 문서를 참고해 주시기 바랍니다.