게임에서 빼놓을 수 없는 것이 AI(Artificial Intelligence)입니다. AI는 컨텐츠를 풍부하게 하는 주 전력이 되며, 플레이어에게 도움을 주거나, 혹은 적대하거나, 혹은 능동적인 상호작용을 통해 플레이어에게 다양한 경험을 제공할 수 있습니다.
저의 경우 AI를 구현할 때 FSM(Finite State Machine - 유한 상태 머신) 방식을 사용했다. 정의할 상태나 상태전이가 적은 소규모 프로젝트에서는 충분했지만, 더 많은 상호작용과 시스템이 있는 대규모 프로젝트에서는 FSM을 사용하여 AI를 구현하기 힘들어집니다. FSM은 다른 기법들에 비해 쉽고 직관적이기 때문에 프로그래머가 아니더라도 누구나 쉽게 설계할 수 있다는 장점이 있지만, 상태와 액션이 다양해지고 복잡해질수록 각 상태의 연결과 유지 보수에 부담이 크고, 상태의 흐름을 파악하기 쉽지 않다는 단점이 있기 때문입니다.
때문에 새로운 프로젝트를 진행하기 위해 또다른 구현방법을 찾아보기 시작했고, 행동 트리(Behaviour Tree - 이하 BT)에 대해 알게 되었습니다.
1. BT란?
행동 트리는 AI 엔터티의 의사결정 흐름을 계층적으로 제어하는 트리 구조입니다. 이 구조에서 트리의 각 노드는 특정한 행동을 나타내며, 가장 하위 노드인 leaves는 실제로 AI를 제어하는 명령을 포함합니다. 이러한 행동 트리는 branch를 형성하는 다양한 유형의 유틸리티 노드들로 구성됩니다. 이러한 노드들은 AI가 트리 아래에서 가장 적합한 명령의 sequence에 도달하도록 제어합니다.
또한, 행동 트리는 특정 기능을 수행하는 하위 트리를 호출하는 노드를 포함할 수 있습니다. 이는 개발자가 매우 설득력 있는 AI 행동을 제공하기 위해 체인으로 묶을 수 있는 행동 라이브러리를 만들 수 있게 합니다. 이렇게 함으로써 모듈화된 구조를 갖게 되어 이해하기 쉽고 유지 보수가 용이해집니다.
행동 트리의 작동 원리는 주로 두 가지 측면으로 설명됩니다.
- 행동 트리의 탐색 순서가 매우 중요하며, 일반적으로 왼쪽에서 오른쪽으로 탐색한다.
- 각 노드는 서로간의 의존성이 없어야하며, 게임 오브젝트나 blackboard에서 정보를 얻어온다.
행동 트리의 노드는 주로 세 가지 상태를 가집니다.
- 성공 상태(Succeed) : 실행 성공
- 실패 상태(Failure) : 실행 실패
- 실행 중인 상태(Running) :노드가 아직 실행 중인 상태.
이러한 방식은 노드의 처리가 게임의 많은 틱에 대해 지속되도록 하기 때문에 행동 트리의 핵심입니다. 이 방식은 트리의 흐름을 전파하고 정의하여 일련의 이벤트와 AI가 원하는 대로 동작하도록 트리 아래쪽의 다른 실행 경로를 제공합니다.
예를 들어, Walk 노드는 경로를 계산하려고 시도하는 시간 동안 Running 상태와 캐릭터가 지정된 위치로 이동하는 데 걸리는 시간을 제공합니다.
만약 어떤 이유로든 경로 찾기가 실패했거나, 또는 대상 위치에 도달하는 캐릭터를 멈추기 위해 걷는 동안 다른 문제가 발생하면, 노드는 부모에게 실패를 반환합니다. 언제든지 문자의 현재 위치가 대상 위치와 같을 경우, Walk 명령이 성공적으로 실행되었음을 나타내는 성공을 반환합니다.
2. 구조
Composite Node
- 하나 이상의 자식을 가질 수 있는 노드
- 자식 노드는 첫 번째에서 마지막 순서로 또는 무작위 순서로 처리됨
- 부모 노드는 자식 노드의 결과를 처리하며, 성패를 부모 노드에게 전달함
- 자식 노드의 결과를 처리하는 동안 자식 노드는 계속해서 부모에게 Running을 반환함
종류
Sequence Node
- 자식 노드를 순서대로 실행하는 노드
- 자식 노드는 왼쪽에서 오른쪽 순서로 깊이 우선 탐색 방식으로 평가됨
- 자식 노드 중 하나가 실패나 실행 중인 상태를 반환하면 즉시 해당 상태를 부모 노드에 반환함
- 모든 자식 노드가 성공을 반환하면 부모 노드에게 성공을 반환함
- AND 게이트와 유사하며, Inverter를 이용하여 NOT 게이트를 사용할 수 있음
- 캐릭터나 게임 월드의 조건을 테스트하는 데 필요한 노드 양을 줄이는 데 유용함
Selector
- 자식 노드 가운데 하나를 실행하는 노드
- 자식 노드는 왼쪽에서 오른쪽 순서로 깊이 우선 탐색 방식으로 평가됨
- 자식 노드 중 하나가 성공이나 실행 중인 상태를 반환하면 즉시 해당 상태를 부모 노드에 반환함
- 모든 자식 노드가 실패를 반환하면 부모 노드에게 실패를 반환함
Decorator Node
- 하나의 자식 노드만 가질 수 있음
- 자식 노드의 결과를 변형하거나 처리를 반복하는 기능을 제공함
- Decorator가 지정하는 조건을 만족할 경우 자식을 실행하고, 만족하지 못할 경우 false를 반환함
종류
Inverter
- 자식 노드의 결과를 뒤집거나 부정함
- 성공은 실패로, 실패는 성공으로 변환됨
- 조건부에서 주로 사용됨
Succeeder
- 자식 노드의 결과에 관계없이 항상 성공을 반환함
- 예상되는 트리의 분기를 처리하거나 고장이 예상되는 경우 유용함
Repeater(Loop)
- 자식 노드를 반복적으로 실행함
- 주로 트리의 맨 아래에서 사용되며, 반복 실행이 필요한 경우에 사용됨
Repeat Until Fail
- 자식 노드가 실패를 반환할 때까지 반복적으로 실행함
- 실패가 발생하면 성공을 반환함
Action Node
- 가장 낮은 수준의 노드로, 자식을 가질 수 없음
- 게임의 특정한 행동을 실행하고, 결과에 따라 성패를 반환함
- 예를 들어, Walk 액션 노드는 캐릭터가 지정된 위치까지 걸어가는 행동을 수행함
- 행동 트리의 가장 강력한 부분으로, 게임의 기능을 정의하고 구현하는 데 사용됨
- 행동 트리를 모듈화하고 재사용할 수 있게 해주며, 게임의 흐름을 정의하는 데 필수적
'유니티' 카테고리의 다른 글
[Unity] 유한 상태 머신(FSM) (0) | 2024.05.03 |
---|