언리얼 엔진에서 혼자 움직이는 AI 캐릭터를 만들어보자
언리얼 엔진으로 게임을 개발하면서 AI 캐릭터를 구현하려고 할 때, 반드시 이해해야 하는 개념이 있다. 바로 AIController, Behavior Tree, Blackboard이다. 처음 언리얼 AI 시스템을 접하면 낯설고 복잡하게 느껴질 수 있지만, 이 세 가지 개념만 정확하게 파악하면 생각보다 깔끔하게 AI를 제어할 수 있다.
나 역시 처음에는 단순한 적 캐릭터 하나 만들기 위해 수많은 언리얼 문서를 뒤지고, 여러 영상들을 보며 헤맸다. 하지만 실제로 몇 가지 프로젝트를 거치면서 이 개념들이 어떻게 유기적으로 연결되는지를 몸으로 익히고 나니, 자연스럽게 AI를 디자인할 수 있게 되었다. 이 글은 그런 나의 실제 경험을 바탕으로, 초심자도 이해할 수 있도록 핵심 개념들을 풀어보려 한다.
1. AIController – AI의 두뇌
AIController는 언리얼 엔진에서 AI 캐릭터를 제어하는 중심적인 클래스이다. 쉽게 말하면 플레이어 캐릭터는 PlayerController가 조종하는 반면, AI 캐릭터는 AIController가 조종한다고 보면 된다.
AIController는 일반적으로 다음과 같은 역할을 수행한다.
- AI가 행동을 시작하거나 멈추도록 지시한다.
- Behavior Tree와 연결하여 AI의 의사결정을 트리거한다.
- 환경 정보를 수집하거나 특정 액션을 실행한다.
예를 들어, AI가 플레이어를 따라가도록 하고 싶다면, MoveToActor나 MoveToLocation 같은 함수를 AIController에서 호출하게 된다. 그리고 이러한 행동의 트리거 조건이나 방식은 Behavior Tree에서 정해주는 방식이다.
중요한 점은, AIController는 Behavior Tree를 실행하는 "컨트롤 허브" 역할을 한다는 것이다. 모든 AI의 행동은 이 컨트롤러를 통해 시작된다.
2. Behavior Tree – AI의 결정 구조를 만든다
Behavior Tree는 말 그대로 나무 구조의 트리 형태로 구성된 AI 결정 시스템이다. 언리얼에서는 직관적인 에디터를 통해 시각적으로 AI의 행동을 설계할 수 있게 지원하고 있다.
Behavior Tree는 크게 세 가지 노드로 구성된다:
- Root Node (루트 노드): 트리의 시작점.
- Composite Node (복합 노드): Sequence, Selector 같은 노드로, 여러 행동을 조합할 수 있다.
- Task Node (작업 노드): 실제 AI가 수행할 작업(이동, 대기, 공격 등).
- Decorator Node (장식 노드): 조건에 따라 행동의 실행 여부를 결정.
- Service Node (서비스 노드): 주기적으로 실행되어 Blackboard 값을 업데이트.
예를 들어, 아래와 같은 간단한 Behavior Tree를 생각해보자:
Root
└─ Selector
├─ Sequence (적이 보이면)
│ ├─ Check Enemy
│ └─ MoveTo Enemy
└─ Patrol
위 구조는 AI가 적을 볼 경우 적에게 이동하고, 보지 못하면 순찰 행동을 하도록 구성된 것이다.
Behavior Tree의 가장 큰 장점은 상황에 따른 유연한 행동 설계가 가능하다는 점이다. 이를 통해 복잡한 AI도 모듈화해서 관리할 수 있다.
3. Blackboard – AI의 기억 장치
Behavior Tree가 실행 로직이라면, Blackboard는 그 로직이 참고할 수 있는 데이터 저장소이다. 말하자면 AI의 머릿속 기억장치라고 보면 된다.
Blackboard에는 변수 형태로 다양한 데이터를 저장할 수 있다. 대표적인 예는 다음과 같다:
- 적 캐릭터의 위치 (Vector)
- 적 캐릭터 자체 (Object)
- 현재 상태 (Enum 또는 Bool)
- 대기 시간 (Float)
Behavior Tree의 Task, Decorator, Service 등은 이 Blackboard 데이터를 기반으로 조건을 판단하거나 행동을 결정하게 된다.
예를 들어, "적이 시야에 보이면 공격한다"라는 로직을 구현하려면, Service 노드가 적 탐지 로직을 실행해 Blackboard에 TargetActor를 저장하고, 이 값이 존재할 경우 Task 노드가 공격 행동을 실행하는 식이다.
Blackboard의 변수들은 Blueprint나 C++ 코드에서도 쉽게 접근 가능하다. 덕분에 유기적으로 다른 시스템과 연동할 수 있다는 장점이 있다.
4. 위의 세 가지가 연결되는 방식 (1~3번의 작동)
이 세 가지 구성 요소는 다음과 같은 흐름으로 연결된다.
- AIController가 특정 시점에 RunBehaviorTree()를 호출한다.
- 연결된 Behavior Tree가 실행되며 루트 노드에서부터 행동을 평가하기 시작한다.
- Blackboard의 값을 바탕으로 행동의 조건을 판단하고, 필요한 Task를 실행한다.
- Service 노드는 주기적으로 상태를 업데이트하며, AI의 상황 인식을 돕는다.
결국 이 세 가지는 하나의 톱니바퀴처럼 맞물려서, 하나의 AI 캐릭터가 지능적인 행동을 하도록 만들어주는 것이다. 위 세가지를 자유자재로 다룰 수 있어야 실제 플레이어처럼 움직이는 AI를 보다 정교하게 만들어낼 수 있다.
5. 실제 사용 경험에서 느낀 팁
- 처음에는 Behavior Tree를 너무 복잡하게 설계하지 말고, 단순한 Patrol → 적 발견 시 추격 정도부터 시작하는 것이 좋다.
- Blackboard 변수 이름은 최대한 직관적으로 설정하자. 프로젝트가 커질수록 헷갈린다.
- Service 노드는 너무 자주 실행하면 성능에 영향을 줄 수 있으니, 타이머 간격을 잘 조절하자.
- AI Perception 시스템과 연동하면, 시야, 청각 등을 활용한 AI를 훨씬 현실감 있게 만들 수 있다.
글 정리
언리얼 엔진에서 AI 캐릭터를 만들기 위해 꼭 알아야 할 세 가지 핵심 개념은 다음과 같다.
구성 요소 | 설명 | 역할 요약 |
AIController | AI 캐릭터의 두뇌 역할 | 행동 트리 실행, 명령 전달 |
Behavior Tree | 트리 구조로 행동 설계 | 의사 결정 및 행동 로직 정의 |
Blackboard | 데이터 저장소 역할 | 행동 조건 판단을 위한 변수 저장 |
이 세 가지는 따로 떼어볼 수 없는 하나의 시스템이다. 처음엔 익숙하지 않지만, 작은 예제를 통해 차근차근 익혀 나간다면 언리얼 AI 시스템의 강력함을 온전히 활용할 수 있을 것이다. 나 역시 그렇게 성장했고, 지금은 다양한 AI 캐릭터를 유연하게 제어할 수 있는 단계에 도달했다.
필요하다면 이 글을 기반으로 시리즈로 확장해서, 앞으로 계속 데디케이티드 서버 환경에서 멀티플레이 FPS 데스매치를 제작하는 글을 작성할 예정이다. 도움이 되었기를 바라며, 언리얼 AI 개발 여정에 조금이나마 도움이 되었으면 한다.