언리얼 오브젝트의 특징과 리플렉션 시스템의 동작원리를 이해하자. 언리얼 오브젝트의 처리 방식을 이해하고 사용예시를 분석하자.

 

 

인프런 이득우님의 '언리얼 프로그래밍 Part1 - 언리얼 C++의 이해' 강의를 참고하였습니다. 
😎 [이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해] 강의 들으러 가기!

 

 

 

목차

     

     


     

     

    언리얼 오브젝트 리플렉션

     

    리플렉션(Reflection)은 프로그램이 실행시간에 자기 자신을 조사하는 기능이다.


     

     

    UPROPERTY()를 붙이는 기준

     

    리플렉션 프로퍼티 변수는 언리얼 엔진의 시스템의 관리(=Garbage Collector)를 받는다.

     

    반면에, 리플렉션 프로퍼티가 아닌 것은 해당 리플렉션에 의존하는 시스템 전부에 보이지 않는다.

    즉, 리플렉션 되지 않은 UObject 포인터 그대로를 저장하면 Garbage Collector(GC)가 레퍼런스를 확인할 수 없다.

    해당 경우는 직접 메모리 관리를 해줘야 한다.


     

     

    Unreal Header Tool (UHT)

     

    • 컴파일 전 리플렉션 시스템을 포함하여 필요한 소스 코드를 만드는 작업을 거치게 되고, 소스 코드들은 .generatred.h에 생성 된다.
      • Intermediate 폴더 내 생성
      • Unreal Build Tool (UBT)과 함께 코드를 분석 후 빌드에 필요한 소스를 제작
    • UHT는 C++ 파서가 아니다.
    • 언리얼 엔진에서 코드를 자동으로 생성하는데 필요한 기능만 제공한다. (실제 C++ 언어를 UHT이 분석해서 컴파일을 진행하는게 아니다!)
    • UHT는 실제 컴파일 과정에 있어 관여하는 부분은 없으며, 정교하지 않다.

     

     

    언리얼 오브젝트의 구성

     

    언리얼 오브젝트에는 특별한 프로퍼티와 함수를 지정할 수 있음

    • 관리되는 클래스 멤버 함수:  UFUNCTION ()
    • 관리되는 클래스 멤버 변수:  UPROPERTY()
    • 에디터와 연동되는 메타데이터를 심을 수 있음

     

    모든 언리얼 오브젝트는 클래스 정보(= UClass)와 함께 함 (※ UClass는 클래스 정보를 담는 클래스다)

    • 클래스(=UClass)를 사용해 자신이 가진 프로퍼티와 함수 정보를 컴파일 타임과 런타임에서 조회할 수 있음

     

    이렇게 다양한 기능을 제공하는 언리얼 오브젝트는 NewObjectAPI를 사용해 생성해야 함

     


     

     

    언리얼 오브젝트의 클래스 기본 오브젝트

     

    Class Default Object (CDO) 클래스 기본 오브젝트 

    • 언리얼 클래스 정보에는 클래스 기본 오브젝트(Class Default Object)가 함께 포함되어 있음.
    • CDO는 언리얼 객체가 가진 기본 값 보관하는 템플릿 객체
    • 한 클래스로부터 다수의 물체를 생성해 게임 콘텐츠에 배치할 때 일관성 있게 기본 값을 조정하는데 유용하게 사용됨
    •  CDO는 클래스 정보로부터  GetDefaultObject 함수를 통해 얻을 수 있음.
    • UClass 및 CDO는 엔진 초기화 과정에서 생성되므로 콘텐츠 제작에서 안심하고 사용할 수 있음.

     

     


     

     

    언리얼 오브젝트 처리

     

    자동 프로퍼티 초기

    • UPROPERTY 속성의 변수들은 자동으로 값이 초기화
      • C++과 달리 가비지 값이 아닌 0으로 채워짐

     

    레퍼런스 자동 업데이트

    • 언리얼 엔진의 자동 메모리 시스템의 이점을 활용

     

    직렬화 Serialization

    • UPROPERTY값은 명시적으로 "transient" (휘발성) 마킹 또는 생성자 이후 기본 값에서 미변경 상태가 아닌 이상 자동으로 읽고 쓰기가 가능하다.

     

    프로퍼티 값 업데이트하기

    • CDO가 변경되면, 기존 배치 된 오브젝트들을 조사
      • 기본 값인 경우:  새로운 값으로 업데이트
      • 값이 상이할 경우:  그대로 둠 ( 의도적으로 바꾸었다고 판단 )

     

    런타임 유형 정보 및 형변환

    • UObject는 항상 자신이 무슨 UClass인지 알고 있음
      • Super를 통해, 부모의 정보 덮어 쓰기에 대한 제어가 쉬워짐
      • Cast를 통해, 파생된 클래스로 안전하게 캐스팅
      • IsA를 사용하여, 오브젝트가 특정 클래스의 것인지 질의할 수 있다

     

     

     

    예제 프로젝트

     


     

    예제 코드

     

    #include "MyGameInstance.h"
    
    UMyGameInstance::UMyGameInstance()
    {
    	// CDO는 하나의 인스턴스
    	// 엔진이 초기화되는 과정에서 CDO 생성. 따라서 생성자 코드를 고치는 경우에는 에디터를 꺼준 후 다시 실행하는게 안전하다.
    	SchoolName = TEXT("기본 학교");
    }
    
    void UMyGameInstance::Init()
    {
    	Super::Init();
    
    	// 동일한 객체를 가리키고 있다
    	UClass* ClassRuntime = GetClass(); // 런타임
    	UClass* ClassCompile = UMyGameInstance::StaticClass();
    	
    	check(ClassRuntime == ClassCompile); // false면 오류 메시지 출력 + 게임 중단
    
    	ensure(false); // 오류 발생 시 에디터가 꺼지지 않고 Output Error Log를 출력하여 에러를 알려줌
    	ensureMsgf(false, TEXT ("일부러 에러를 발생시킨 코드"));
    
    	UE_LOG(LogTemp, Log, TEXT("학교 클래스 이름: %s"), *ClassRuntime->GetName());
    
    	SchoolName = TEXT("울랄라 학교");
    	UE_LOG(LogTemp, Log, TEXT("학교 이름: %s"), *SchoolName);
    	UE_LOG(LogTemp, Log, TEXT("학교 기본 이름: %s"), *GetClass()->GetDefaultObject <UMyGameInstance>()->SchoolName);
    }

     


     

     

    에디터를 재시작 해야되는 경우는?

     

     

    헤더 파일에 리플렉션 정보의 이런 구조를 변경하거나,
    생성자 코드에서 Class Defualt Object(CDO) 기본값을 변경하는 경우에는
    에디터를 끄고 컴파일해서 다시 실행하는 것이 안전하다.