들어가기 앞서 해당 글은 언리얼 엔진 공식문서와 인프런 '이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해' 강의 를 참고로 작성되었습니다.

 

 

 언리얼의 핵심 기능 중 하나가 바로 프로퍼티 시스템(property system)이다. 해당 기능에 대해선 공식문서에서 설명하고 있다. 

 

 첫 문단을 요약하면 c++에는 없는 리플렉션 기능을 구현하여 엔진의 근간을 이룬다는 것이다. 그 후에 서술되는 것은 언리얼 리플렉션. 즉, 프로퍼티 시스템을 간략한 주의점과 함께 어떤식으로 활용하는지를 설명한다.

 

 강의는 공식문서를 참고하면서 CDO(ClassDefaultObject)를 언급하며 CDO의 특징과 프로퍼티를 어떻게 쓰는지를 보여준다.

 

 필자는 이미 언리얼을 이용하여 c++로 구현하면서 맛을 봤기 때문에 사용과 어떤식으로 동작하는지는 어려움이 없었으나, 시원하게 해결되지 않는 부분이 있었다.

 명확히 '어떤 시스템이다!' 라는 것이 정리 되지않았고 무엇보다 프로퍼티 시스템과 CDO의 연결점을 찾지 못해 고민을 했다. 강의에서는 CDO가 뜬금없이 튀어나와 이런 것이라고 설명을 해주는데 직접적인 프로퍼티 시스템과의 연관성을 설명해주진 않았다.(물론 필자가 그냥 놓친 것 일수도 있다)

 

 해당 글에서는 그래서 왜 프로퍼티가 중요한지. CDO와는 대체 어떻게 이어지는지를 이야기하려 한다.

 

 

 

 우선 리플렉션이(Reflection)란 무엇이냐?

 구글에 검색해보면 흔히, 아니 거의 모든 글에서 다음과 같이 설명하고 있다.

 

 "리플렉션(Reflection)은 프로그램이 실행 중(런타임)에 자기 자신의 구조를 검사하여 변수나 매소드에 접근할 수 있는 기능."

 

 언리얼 프로퍼티 시스템 공식문서의 첫 줄 또한 똑같이 설명하고 있다. 그럼 해당 기능이 왜 중요한 것일까? 다른 글에서는 흔히 자바로 설명을 하지만 여기서는 언리얼 프로퍼티 시스템을 가지고 설명하겠다.

 

 

 위는 third person 프로젝트의 기본 캐릭터의 헤더파일이다.

 

 여기서 눈여겨 볼 키워드는 UCLASS() 매크로다. 언리얼의 프로퍼티 시스템을 사용하려면 해당 매크로 선언을 해 줘야한다. 

 

 UCLASS() 매크로를 선언하면 컴파일 과정에서 UHT(Unreal Header Tool)이 실행되고 UHT는 컴파일 단계에서 헤더의 매크로를 분석하여 해당 매크로에 해당하는 프로퍼티 시스템 코드를 담은 .generated.h 파일을 생성한다. 이로서 해당 클래스는 언리얼의 프로퍼티 시스템을 쓸 수 있게 되었다. 정확하게는 언리얼의 관리를 받게됐다는 표현이 맞겠다. 이 부분이 중요하다.

 

UCLASS()를 선언한 클래스는 UClass타입으로 하나의 정보를 들고 있게 되는데 그것이 바로 CDO(ClassDefaultObject)이다.

 

 CDO(ClassDefaultObject)

 CDO(ClassDefaultObject)는 말 그대로 해당 클래스의 기본값. 클래스의 이름, 변수, 함수의 정보를 들고 있다. 아래는 간단한 실습이다.

 

UMyGameInstance 클래스는 UPROPERTY() 매크로 선언을 한 MyName변수를 들고 있다.

 

 

 CDO는 생성자가 호출될 때 초기화 되는데(정확히는 생성자 끝에서), CDO의 값에 대해 알아보기 위해 로그를 찍어 보았다.

 

 MyName변수는 생성자에서 '기본 이름'으로 초기화 되었고 Init()함수에서 '놀고있는메모리' 로 변경 해 주었다. 그리고 Line: 24~25에 각각 로그를 찍어줄 건데 하나는 그대로 MyName변수를 출력하고 하나는 GetDefaultObject로 CDO에 있는 MyName을 출력할 것이다.

 

출력 결과

 

 출력 결과는 위와 같이 나온다. 값을 다시 설정 해 줬는데도 CDO의 값은 변함이 없다는 것을 알 수 있다. 

 

 

 그럼 바뀌지도 않는 이 정보를 언리얼 엔진에서 어떻게 쓰이나?

 프로그래머가 매크로 선언(UPORPERTY,UFUNCTION 등)으로 디테일 창이나 블루프린트에서 볼수 있는 변수나 메서드가 바로 이 CDO의 정보를 가져와 '초기화'한 것이다.

 

 이 CDO는 위에서 말했듯 생성자가 호출될 때 만들어 지기 때문에 안전하게 접근할 수 있다.

 

해당 지점에 브레이크 포인트를 걸면
엔진 초기화 75% 단계에서 멈추고
해당 브레이크 포인트에 걸리게된다.
f10을 누르고 생성자의 끝에서 f11을 누르면
GetDefaultObject에서 CreateDefaultObject가 호출되는 걸 볼 수 있다.

 

이와 같이 엔진 초기화 단계에서 생성되기 때문에(만약 문제가있다면 여기서 걸러지기 때문에) 프로그래머가 엔진을 이용하여 프로그래밍을 할 때(런 타임 때) 안전하게 접근하여 인스턴스를 생성하는 강력한 시스템이 아닐 수 없다.  

 

이 CDO의 정보들은 findclass함수나 newobject등으로 (런타임중)클래스를 생성할 때 안전하게 접근하여 쓰이게 된다.

 

 또한 CDO가 없다면 블루프린트를 생성할 때 어떤 값을 참조하여 초기값을 설정할지 모르게 된다. 즉, 새로운 인스턴스가 생성될 때 그 새로운 인스턴스를 어떤값으로 초기화해야 하는지가 불분명해지며, 이로 인해 초기화 과정이 복잡해질 수 있다는 것이다. 디테일 패널에서 보는 초기값이 그러하다. 

 

 이상이 바로 프로퍼티 시스템(리플렉션)의 '자기 자신의 구조를 검사하여 런 타임 때 변수와 매소드에 접근 가능한 강력한 기능' 의 의미와 CDO의 중요성이다. 

 

 또한 라이브 코딩 시 엔진의 디테일창에 변경된 값이 엔진이 꺼진 후 다시 킬 때 그 값이 날아 가버리는 현상이 있다. 이것이 바로 컴파일 단계에서 만들어지는 복사 값인 CDO값을 가져온 것이기 때문에, 컴파일 시 생성된 CDO의 기본값이 적용되어 라이브 코딩 시 해당 정보는 업데이트 되지 않아 생기는 문제로 볼 수 있겠다.

+ Recent posts