안녕하세요!
오늘은 AI 시스템을 개선했던 일에 대해 써보려 합니다.
0. 기존 시스템
게임 초기에는 단순한 몬스터밖에 없었습니다.
몇가지 상태가 있고, 적절한 타이밍에 전환하는 식으로 동작하였습니다. (State Machine)
그리고 이벤트 컷씬에서 몇가지 간단한 명령을 수행할 수 있었습니다. (Wait, Sleep, Move등등)
단순한 시스템이지만 큰 문제없이 잘 써왔습니다.
하지만 점점 복잡한 AI를 구현하게 되면서 여러 문제가 발생했고, 몇가지 큰 변화가 있었습니다.
1. State Machine 기반에서 Behaviour Tree로 변경
<언리얼 엔진의 Behaviour Tree>
Behaviour Tree를 잘 모르시는 분들을 위한 대략적인 설명:
Behaviour Tree는 AI의 행동 매커니즘을 표현하는 데이터 구조입니다.
기본적으로 루트에서 시작해서 Tree를 타고 들어가면서 현재 상황에 알맞은 상태로 들어갑니다.
사실 그게 끝이라면 Decision Tree랑 차이가 없게 되는 건데요.
Behaviour Tree는 컨텍스트가 있다는 점에서 차이가 있습니다.
매번 루트부터 시작해서 노드를 평가하는 것이 아니라, 이미 들어가있으면 거기서부터 노드를 체크합니다.
Sequence라고 한다면 자식 노드를 순서대로 하나씩 수행하는 방식이고, Selector라고 한다면 자식 노드 중 성공하는 하나가 나올 때까지 시도하는 식입니다.
이런 점 때문에 복잡한 행동을 표현할 수 있고, 많은 상용 게임에서 쓰고 있습니다.
저희도 원래 State Machine 기반을 쓰고 있었지만 다음과 같은 이유로 바꾸게 됐습니다.
우선 State Machine기반일 때, 상태를 바꾸는 전환 로직이 코드 곳곳에 숨어있었습니다.
그래서 AI가 어떤 행동 매커니즘을 가지는지 확인하기 위해서는 코드 전체를 읽어봐야 했습니다.
반면 Behaviour Tree는 트리만 보면 AI의 행동 매커니즘을 파악할 수 있다는 장점이 있습니다.
그리고 복잡한 행동을 구현할 때에도 Behaviour Tree가 더 낫습니다.
예를 들어서 State Machine은 단순히 적이 삼단 공격을 한다고 했을 때에도 카운트 변수를 증가시키면서 체크하는 로직이 필요합니다.
반면 Behaviour Tree에서는 Sequence 노드에 자식으로 공격 노드를 3개 넣으면 바로 구현이 됩니다.
그리고 복잡한 행동의 경우, 트리를 크고 깊게 작성하면 구현이 됩니다.
트리가 크더라도 노드끼리 서로 영향을 미치지 않기 떄문에 복잡성이 늘어나지 않아 작성하는데 부담이 크지는 않습니다.
코드 기반 Behaviour Tree입니다.
일반적으로 Behaviour Tree는 GUI기반 그래프 방식을 쓰지만 가독성에서 장점이 있다고 생각해서 코드 기반으로 만들었습니다.
디버거도 만들어서 쓰고 있습니다.
브레이크 포인트, 트리가 fail했을 때 추적등 여러 기능이 있어서 좀 더 편리하게 디버깅하고 있습니다.
2. 더미 모드 지원
더미를 키면 명령 외에는 행동하지 않는 상태가 됩니다.
끄면 다시 원래대로 돌아고요.
컷씬에서 AI 행동을 제어하기 위해 구현하게 됐습니다.
그리고 누가 dummy 플래그를 바꿨는지 추적할 수 있는 기능을 추가하여 더 편하게 디버깅할 수 있게 됐습니다.
3. 명령 인터페이스 통일
명령 타입마다 파라미터를 정의할 수 있고, 에디터에서 자동으로 파라미터들이 나옵니다.
기본 명령 세트가 있고, 캐릭터 마다 전용 명령도 정의할 수 있습니다.
그리고 Override를 지원해서 기본 명령 코드 유연하게 재사용할 수 있습니다.
이런 개선 사항으로 명령을 편리하게 내릴 수 있게 됐습니다.
읽어주셔서 감사합니다!
인디크래프트2021 때 재미있게 즐겼던 프로스토리를 여기서 또 보네요! 진짜 응원합니다!!
오 예전에 픽셀퍼팩트 찾다가 본 게임