이전 시간에 구현해두었던 Enemy AI의 추적(Patrol) 기능에 한 가지 문제점이 발생하였다.
한 명의 Enemy만 추적을 수행하면 아무런 문제가 없는 듯 보이지만, 두 명의 Enemy를 각각 배치하고, 서로 다른 Patrol Path 액터(Spline Component가 포함된 경로 액터)를 지정해주면 바로 문제점이 나타났다.
원하던 기능은 각각의 Enemy가 할당된 Spline Component를 따라 순찰하는것이었지만, 실제로는 두 Enemy가 똑같은 SplineComponent를 순찰하며 서로에게 할당된 Spline을 번갈아가며 랜덤하고 이상하게 순찰이 진행되었다.
문제점은, 작성한 Patrol Task 클래스에서 이동할 위치 변수인 FVector Location 값이 두 Enemy에게 공유되어 사용됐기 때문이었다.
블루프린트에서는 비헤이비어 트리에 선언한 Task 객체의 변수들이 인스턴스마다 개별적으로 관리되기 때문에 별다른 공유 데이터 문제는 발생하지 않았었다.
그러나 C++ 클래스에서 생성한 Task의 변수는 클래스 수준의 변수로써, 해당 클래스의 모든 인스턴스가 변수 값을 공유한다.
즉, 같은 클래스의 다른 인스턴스들은 같은 변수에 접근하여 값을 공유하게 되는 것이다.
이러한 문제를 해결하기 위해 Tick 함수에서 Location 변수를 초기화하기도 했지만, Tick 함수에서 위치를 작성하는것은 Spline 순찰만 성공시킬 뿐 랜덤 위치를 지정하는 순찰방법에서 또 다른 문제를 야기했다.
Tick 함수가 호출될 때마다 새로운 Location 값이 지정되기 때문에 랜덤 Location 순찰이 정상 작동할 수 없는 것이었다.
최종적인 해결 방법은 블랙보드에 Enemy가 이동해야하는 Patrol Location 키 값을 지정하여 객체 간 개별적인 위치 변수를 갖도록 구현하였다.
실제로 어떻게 문제를 해결했는지 과정을 설명해보았다.
먼저, 블랙보드 키 값으로 Patrol Location을 추가하였다.
💻 CAIBehaviorComponent
이런 블랙보드 키 값을 가져오기 위해 PatrolLocationKey 변수를 CAIBehaviorComponent에 추가하였다.
이러한 PatrolLocationKey값을 설정하고 가져올 수 있는 Set/Get 함수도 작성하였다.
💻 CBTTaskNode_Patrol
Patrol Task 클래스의 ExecuteTask 함수에서는 Enemy_AI가 가지고 있는 비헤이비어트리 컴포넌트를 불러와 PatrolPath가 존재한다면, 비헤이비어의 PatrolLocation Key 값을 Spline의 위치 값으로 초기화할 수 있도록 하였다.
Tick 함수에서는 Enemy_AI의 Patrol Location 키 값을 받아와서 순찰하는 위치들에 대해 순찰이 성공했는지를 계속해서 검사하였다.
컴파일 후 프로그램을 실행시켜보면, Enemy가 각각에게 할당된 Patrol Path대로 순찰을 수행하도록 잘 구현되었다.