UE4 에는 게임 개발에 사용하기 좋은 C++ 라이브러리가 많이 있습니다만, 규모가 큰 코드 프로젝트에서는 어디서 찾을지 항상 명확한 것은 아닙니다. 이 글에서는 특히나 유용하여 확인할 만한 가치가 있는 부분을 몇 가지 짚어보고 싶습니다. 자세한 정보는 API 문서의 'Core' 부분을 읽어보시기 바랍니다. 문서(영문).
컨테이너
저장상의 요구 충족을 위해, UE4 에는 사용할 수 있는 컨테이너 클래스가 전반적으로 구비되어 있으며, 다수는 전통적으로 C++ 표준 라이브러리의 일부였을 기본 함수성을 미러링한 것입니다. 솔직히 담을 수 없는 유일한 것은 이 모든 클래스에서 오는 기쁨 뿐일 것입니다!…미안요.
일반적인 컨테이너
TArray
(Engine\Source\Runtime\Core\Public\Containers\Array.h)
TArray 는 템플릿화된 동적인 크기의 배열로, UE4 콘테이너 중 가장 흔히 사용되는 것입니다. 동적 배열에서 기대할 수 있는 모든 기능은 물론 UPROPERTY 도 완벽 지원됩니다. TArray 의 API 에는 추가적으로 TArray 를 스택이나 힙 구조체로 간주할 수 있는 함수성이 제공됩니다.
TArray 는 UPROPERTY 로 선언 가능하기에, 자주 에디터 프로퍼티 창에 표시되고 네트워크 리플리케이션 뿐만 아니라 자동 UPROPERTY 시리얼라이제이션 대상이 되기도 합니다. 이 기능의 결과, TArray 는 종종 게임플레이 코드 구현시 선택되는 컨테이너입니다.
C++ Standard Template Library (STL) vector 클래스를 사용해 본 적이 있다면, TArray 야 말로 반가운 친구입니다.
TSet
(Engine\Source\Runtime\Core\Public\Containers\Set.h)
TSet 은 수학 집합 개념의 템플릿화된 구현으로, 교집합 합집합 차집합과 같은 일반적인 집합 연산 뿐만 아니라 한 요소가 집합의 일부인지 아닌지 빠르게 확인할 수 있는 기능까지 제공합니다 (PeopleWhoLoveTSet.Contains(Me); // 항상 true).
주의: TArray 와는 달리, TSet(과 TMap)은 UPROPERTY 로 직접 지원되지 않기에, 자동 리플리케이션, 시리얼라이제이션 등이 불가능합니다. TSet (또는 TMap) 이 UObject 강 레퍼런스(예: TSet<UObject*>)와 함께 사용된다면, 해당 레퍼런스가 제대로 시리얼라이즈되어 가비지 콜렉션 가능한지 사용자가 확인해 줘야 합니다. 누군가가 쓰레기는 치워야지요…
TSet 은 STL 집합 클래스와 유사하나, UE4 구현은 해싱을 기반으로 합니다. 새로운 유형을 만들고 TSet (또는 TMap) 에서 사용하려는 경우, 해당 유형 해시를 위해 간단한 함수를 구현해 줘야 합니다: uint32 GetTypeHash(const YourType& TypeVar). 예제가 더 필요하다면, 코드 베이스에 참고해 볼 수 있는 예제가 많이 있습니다.
TMap
(Engine\Source\Runtime\Core\Public\Containers\Map.h)
TMap 은 템플릿화된 데이터 구조체로, 한 유형에서 다른 유형으로의 (키-값 짝) 매핑을 빠른 요소 추가, 제거, 확인 기능을 포함해서 가능하게 해 줍니다. 다른 프로그래밍 언어에서 오신 분들은, TMap 이 나타내는 구조체를 'dictionary' (딕셔너리)로 알고 계실 수도 있습니다.
TSet 과 마찬가지로 TMap 역시 UPROPERTY 선언이 불가능합니다.
TMap 은 C++ STL map 클래스와 비교되지만, UE4 구현은 해싱을 기반으로 합니다.
Iterator
사용법이 C++ STL 과 똑같지 않기는 해도, UE4 컨테이너에는 이터레이터가 제공됩니다. 각 컨테이터 유형마다 지원되는 이터레이터를 확인할 수 있지며, 일반적으로 const / non-const 이터레이터를 사용할 수 있습니다.
예제:
// Example direct from the engine source:
// Initialize an iterator from the provided array (InPackages)
for (TArray<UPackage*>::TConstIterator PkgIter(InPackages); PkgIter; ++PkgIter)
{
// Access the element at the current position of the iterator with the * operator
UPackage* CurPackage = *PkgIter;
C++11 팬인 (그리고 게으른) 경우, 이터레이터에 auto 키워드를 사용할 수도 있습니다:
for (auto FileIt = Files.CreateConstIterator(); FileIt; ++FileIt)
{
const FString FileExtension = FPaths::GetExtension(*FileIt);
소팅
기본 소팅 옵션에 추가로, 소팅을 지원하는 UE4 컨테이너는 predicate 오브젝트를 통해 커스텀 소팅이 가능하기도 합니다.
예제:
// Custom struct written to serve as the predicate for sorting. Given two constant references to elements
// in the data structure (anim notify events), sort them according to their trigger time.
struct FCompareFAnimNotifyEvent
{
FORCEINLINE bool operator()(const FAnimNotifyEvent& A, const FAnimNotifyEvent& B) const
{
return A.GetTriggerTime() < B.GetTriggerTime();
}
};
// Sort the notifies array (TArray<FAnimNotifyEvent>) with the custom predicate
Notifies.Sort(FCompareFAnimNotifyEvent());
다른 컨테이너
TArray, TSet, TMap 은 가장 자주 사용되는 UE4 컨테이너이지만, 유일무이한 것은 아닙니다! 그 삼총사와 아이들에 대한 소스 코드를 확인해 보시려면, Engine\Source\Runtime\Core\Public\Containers 디렉토리를 보시면 됩니다.
스트링 처리
(Engine\Source\Runtime\Core\Public\Containers\UnrealString.h)
(Engine\Source\Runtime\Core\Public\UObject\NameTypes.h)
(Engine\Source\Runtime\Core\Public\Internationalization\Text.h)
UE4 는 스트링의 상호 처리에 있어 알아둬야 하는 세 종류의 클래스를 제공합니다: FString, FName, FText 입니다. 각각 저마다의 용도와 최적의 용례가 있으며, 이 문서(와 그 문서에 링크가 제공된 참고서)에 자세히 설명되어 있습니다.
수학
(Engine\Source\Runtime\Core\Public\Math\UnrealMathUtility.h)
(Engine\Source\Runtime\Core\Public\GenericPlatform\GenericPlatformMath.h)
수학 없이 게임이라니요?! 다행히도 UE4 에는 매우 탄탄한 크로스 플랫폼 수학 라이브러리가 있으며, 일반적으로 FMath 안의 스태틱 함수 시리즈로 구현됩니다. FMath 는 매우 간단한 것에서부터 복잡한 것에 이르기까지 다양한 범위의 수학 연산을 아우르고 있습니다. 수학 관련 작업을 시작하기 전, 두 헤더 파일 모두 둘러보고 이미 작성된 내용에 대한 개념을 확실히 잡아둘 가치가 있습니다!
마무리
UE4 에서 알아둬야 할 중요 라이브러리에 대해 유용한 미니 투어가 되었으면 합니다만, 정말이지 수박 겉핥기 수준일 뿐입니다. 엔진에는 어떤 용도로든 사용할 수 있는 코드가 가득합니다.
이 글에 대한 피드백도 있으시다면 환영합니다! 너무 광범위한가요? 너무 헛갈리나요? 개그가 너무 식상한가요? 질문이나 코멘트는? UE4 커뮤니티 포럼 에 참가하시거나 트위터 @EpicIrascible 에서 저랑 놀아요. 한글 사용자 분들을 위해 네이버 카페도 준비되어 있습니다.