본문 바로가기

Memorize: RECALL

Weapon 초기화를 위한 새로운 설계

 원래 Player와 AI의 Weapon 초기화를 BeginPlay에서 수행했다. 단말 Blueprint의 BeginPlay에서 직접 Wepaon을 생성하는 방식으로 동작하였고, 기존에는 큰 문제가 없었다. 그러나 Anim Montage 등의 각종 Animation Data를 Weapon에 종속적으로 하고, Unequip 상태를 나타내는 Dummy Weapon의 생성 과정에서 다수의 Bug가 발생했고, Refactoring을 감행했다.

Weapon 종속적인 Animations

 

 Refactoring 중 문제가 발생했다. Player와 AI에 모두 적용 가능한 무기 생성 코드를 어떻게 작성해야 할까? BeginPlay에서 수행할 경우, Unequip Weapon의 Getter를 제작해야 하며 Base Class -> Blueprint -> Child Class 순으로 BeginPlay가 호출되어 예상치 못한 오류가 발생하게 된다. 그러나 Blueprint에서 Weapon을 생성할 적절한 Timing은 존재하지 않았다.

 

 해결책의 첫 접근 방식은 간단했다. Blueprint가 아닌 C++ Class에 Weapon 생성의 책임을 부여하면 해결할 수 있지 않을까? Blueprint에서 생성해야 할 Weapon들에 대한 정보를 Base Class에 넘겨주면, 이를 바탕으로 Weapon을 생성하는 것이다. 이 설계를 이용하면 Blueprint의 Weapon의 생성에 구애받지 않고 Initialize를 수행할 수 있었다.

대표적인 Initialize인 Data Table에서 Mob Character의 값 불러오기

 

 이제 남은 것은 Blueprint에서 Weapon 생성에 필요한 정보를 얻어오는 것과, BeginPlay에서 Player와 AI 별 Weapon 생성을 구현하는 것이었다. 우선 Weapon 생성에 필요한 정보는 오직 Weapon의 이름이다. 그리고 Player는 여러 Weapon을 사용한다. 그리고 이를 모두 만족하는 Type은 TArray<FName>이다. 이를 만족하는 BlueprintImplementableEvent를 Base Class에 두고 Blueprint에서 구현하는 방법을 이용해 첫 번째 문제를 해결할 수 있었다.

Ai Character의 Get Weapon Names 구현체

 마지막 문제는 Virtual Function을 통해 해결하였다. BeginPlay에서 같은 Function을 호출하는데 다른 동작을 수행해야 하므로, Virtual Function이야말로 제격이다. Base Class에 TArray<FName>을 Parameter로 받는 Virtual Function을 선언하고 Ai의 Weapon 생성 코드를 작성했다. 그리고 Player Character Class에서 이를 Specialization해 손쉽게 해결할 수 있었다. 여담으로 Blueprint에서 얻은 Weapon들의 이름은 이 Function에서만 사용하므로 Rvalue-Reference를 통해 최적화할 수 있었다.

Player Character의 CreateWeapons 구현 Code