티스토리 뷰
728x90
언리얼 엔진 오브젝트 시스템 개요
언리얼 엔진은 C++ 위에 자체적인 오브젝트 관리 시스템(UObject System)을 구축했습니다. 이 시스템은 리플렉션(Reflection), 가비지 컬렉션(Garbage Collection), 직렬화(Serialization), 에디터 통합 등 다양한 기능을 제공합니다. UClass
와 CDO는 이 시스템의 핵심적인 부분입니다.
UClass 란 무엇인가?
UClass
는 런타임(Runtime)에서 특정 C++ 클래스에 대한 정보를 담고 있는 UObject입니다. 쉽게 말해, 게임이나 에디터가 실행되는 동안 해당 클래스의 "설명서" 또는 "메타데이터" 역할을 합니다.
- 역할: 클래스의 이름, 부모 클래스, 해당 클래스가 포함하는 프로퍼티(UPROPERTY로 선언된 변수들), 함수(UFUNCTION으로 선언된 함수들), 클래스 플래그 등의 정보를 가지고 있습니다.
- 생성: Unreal Header Tool (UHT)이
GENERATED_BODY()
매크로와UCLASS()
매크로가 포함된 헤더 파일을 파싱하여 각 클래스에 대한UClass
정보를 생성하는 코드를 자동으로 만들어냅니다. - 용도:
- 리플렉션: 런타임에 클래스의 구조(프로퍼티, 함수 등)를 파악하고 접근하는 데 사용됩니다. 이는 블루프린트 시스템, 에디터 디테일 패널, 네트워크 리플리케이션 등에서 광범위하게 활용됩니다.
- 객체 생성: 특정 클래스의 새 인스턴스를 생성할 때(
NewObject
,SpawnActor
등) 어떤 클래스를 만들지 지정하는 데 사용됩니다. - 타입 검사:
IsA<T>()
와 같은 함수를 통해 객체가 특정 클래스 또는 그 자식 클래스의 인스턴스인지 확인할 때 사용됩니다.
CDO (Class Default Object) 란 무엇인가?
CDO는 Class Default Object(클래스 기본 오브젝트)의 약자입니다.
- 정의: 모든
UClass
는 자신과 연결된 단 하나의 CDO 인스턴스를 가집니다. 이 CDO는 해당 클래스가 로드될 때(엔진/에디터 시작 시 또는 모듈 로드 시) 자동으로 생성되는 실제 객체 인스턴스입니다. - 역할: 해당 클래스의 기본값(Default Values)을 저장하는 템플릿 역할을 합니다. 클래스의 C++ 생성자에서 초기화되거나, 헤더에서
UPROPERTY
에 직접 할당된 초기값들이 CDO에 반영됩니다. - 생성:
UClass
가 메모리에 로드될 때 엔진에 의해 자동으로 생성되며, 해당 클래스의 생성자를 호출하여 초기화됩니다. - 용도:
- 기본값 제공:
NewObject<T>()
또는SpawnActor<T>()
등을 사용하여 해당 클래스의 새 인스턴스를 생성할 때, 새로 생성된 객체의 프로퍼티들은 CDO의 프로퍼티 값으로 초기화됩니다. 즉, CDO는 객체 생성 시 "기본 상태"를 제공하는 원본 역할을 합니다. - 템플릿/원형(Archetype): 블루프린트 클래스는 C++ 클래스로부터 파생되는데, 블루프린트에서 설정하는 기본값들은 해당 블루프린트의 CDO(정확히는 GeneratedClass의 CDO)에 저장됩니다.
- 성능: 런타임에 클래스의 기본 프로퍼티 값을 알아내야 할 때, 리플렉션 정보를 매번 파싱하는 것보다 이미 생성된 CDO 인스턴스에서 값을 읽어오는 것이 더 빠릅니다.
- 에디터 통합: 에디터의 디테일 패널에서 클래스의 기본값을 보거나 수정할 때 내부적으로 CDO (또는 블루프린트의 경우 해당 GeneratedClass의 CDO)와 상호작용합니다.
- 기본값 제공:
UClass와 CDO의 관계
UClass
는 클래스에 대한 설명/메타데이터입니다. (예: "이 클래스에는 'Health'라는 이름의 float 변수가 있다.")- CDO는 해당 클래스의 실제 인스턴스이며, 모든 프로퍼티의 기본값을 가지고 있습니다. (예: "이 클래스의 'Health' 변수 기본값은 100.0f 이다.")
- 모든
UClass
객체는 내부적으로 자신의 CDO를 가리키는 포인터를 가지고 있습니다.
코드 예제
아래는 UClass
와 CDO를 사용하는 간단한 예제입니다.
1. 예제 클래스 정의 (MyObject.h
)
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MyObject.generated.h"
UCLASS(Blueprintable, BlueprintType) // UCLASS 매크로를 통해 UObject 시스템에 등록
class YOURPROJECTNAME_API UMyObject : public UObject
{
GENERATED_BODY() // UHT가 필요한 코드를 생성하도록 함
public:
// 생성자에서 기본값 설정
UMyObject();
// UPROPERTY 매크로를 사용하여 리플렉션 시스템에 등록하고 기본값 설정
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "My Object Properties")
int32 MyIntProperty;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "My Object Properties")
FString MyStringProperty;
UPROPERTY(VisibleAnywhere, Category = "My Object Properties")
float MyFloatProperty_NoInit; // 생성자에서 초기화할 프로퍼티
};
2. 예제 클래스 구현 (MyObject.cpp
)
#include "MyObject.h"
UMyObject::UMyObject()
{
// 생성자에서 프로퍼티 기본값 설정
MyIntProperty = 10;
MyStringProperty = TEXT("DefaultString");
MyFloatProperty_NoInit = 99.9f; // 여기서 설정된 값이 CDO에 저장됨
}
3. UClass 및 CDO 사용 예제 (예: 다른 Actor 클래스 내부)
#include "MyObject.h" // 위에서 정의한 클래스 포함
#include "Engine/Engine.h" // GEngine 사용을 위해
// ... Actor 클래스의 함수 내부 ...
void AMyActor::SomeFunction()
{
// 방법 1: StaticClass()를 사용하여 UClass 얻기 (컴파일 타임에 클래스 타입을 알 때)
UClass* MyObjectClass = UMyObject::StaticClass();
if (MyObjectClass)
{
UE_LOG(LogTemp, Warning, TEXT("UMyObject의 UClass 이름: %s"), *MyObjectClass->GetName());
// UClass로부터 CDO 얻기 (템플릿 인자로 클래스 타입 명시)
UMyObject* DefaultObject = MyObjectClass->GetDefaultObject<UMyObject>();
// 또는 UObject* DefaultObjectRaw = MyObjectClass->GetDefaultObject();
if (DefaultObject)
{
UE_LOG(LogTemp, Warning, TEXT("CDO의 MyIntProperty 기본값: %d"), DefaultObject->MyIntProperty);
UE_LOG(LogTemp, Warning, TEXT("CDO의 MyStringProperty 기본값: %s"), *DefaultObject->MyStringProperty);
UE_LOG(LogTemp, Warning, TEXT("CDO의 MyFloatProperty_NoInit 기본값: %f"), DefaultObject->MyFloatProperty_NoInit);
// 주의: CDO의 값을 직접 수정하는 것은 일반적으로 권장되지 않습니다.
// CDO는 템플릿이므로, 런타임에 CDO를 변경하면 이후 생성되는 모든 객체에 영향을 줄 수 있습니다.
// DefaultObject->MyIntProperty = 100; // 이런 코드는 피하는 것이 좋습니다.
}
// 새 객체 인스턴스 생성
UMyObject* NewMyObjectInstance = NewObject<UMyObject>(this, MyObjectClass); // this는 Outer 객체 지정
if (NewMyObjectInstance)
{
// 새로 생성된 객체의 프로퍼티 값은 CDO의 값으로 초기화됩니다.
UE_LOG(LogTemp, Warning, TEXT("새 인스턴스의 MyIntProperty 초기값: %d"), NewMyObjectInstance->MyIntProperty); // 출력: 10
UE_LOG(LogTemp, Warning, TEXT("새 인스턴스의 MyStringProperty 초기값: %s"), *NewMyObjectInstance->MyStringProperty); // 출력: DefaultString
// 새 인스턴스의 값은 자유롭게 수정 가능
NewMyObjectInstance->MyIntProperty = 500;
UE_LOG(LogTemp, Warning, TEXT("새 인스턴스의 MyIntProperty 수정 후 값: %d"), NewMyObjectInstance->MyIntProperty); // 출력: 500
}
}
// 방법 2: 기존 객체 인스턴스로부터 UClass 얻기
UMyObject* ExistingObject = NewObject<UMyObject>(); // 예시로 객체 하나 생성
if (ExistingObject)
{
UClass* ClassFromInstance = ExistingObject->GetClass();
if (ClassFromInstance)
{
UE_LOG(LogTemp, Warning, TEXT("기존 객체로부터 얻은 UClass 이름: %s"), *ClassFromInstance->GetName());
// 마찬가지로 CDO 접근 가능
UMyObject* CDOFromInstanceClass = ClassFromInstance->GetDefaultObject<UMyObject>();
if (CDOFromInstanceClass)
{
UE_LOG(LogTemp, Warning, TEXT("기존 객체의 클래스 CDO의 MyIntProperty: %d"), CDOFromInstanceClass->MyIntProperty);
}
}
// ExistingObject->ConditionalBeginDestroy(); // 예시로 생성한 객체 정리 (GC가 처리하도록 둠)
}
}
예제 설명:
UMyObject
클래스를UCLASS()
매크로와 함께 정의하여 언리얼 오브젝트 시스템의 일부로 만듭니다.UPROPERTY()
매크로를 사용하여 멤버 변수들을 리플렉션 시스템에 노출시키고, 일부는 생성자에서 기본값을 설정합니다.- 다른 클래스(
AMyActor::SomeFunction
) 내에서:UMyObject::StaticClass()
를 호출하여UMyObject
의UClass
객체를 얻습니다.MyObjectClass->GetDefaultObject<UMyObject>()
를 호출하여 해당UClass
에 연결된 CDO를 얻습니다.- CDO의 프로퍼티 값을 읽어 기본값을 확인합니다. 이 값들은
UMyObject
생성자에서 설정한 값과 동일합니다. NewObject<UMyObject>()
를 사용하여UMyObject
의 새 인스턴스를 생성합니다. 이 때, 새 인스턴스의 프로퍼티들은 CDO의 값으로 자동 초기화됩니다.- 새 인스턴스의 프로퍼티 값은 이후 자유롭게 변경할 수 있습니다.
- 기존 객체의
GetClass()
멤버 함수를 통해서도 해당 객체의UClass
를 얻을 수 있습니다.
요약
UClass
: 클래스의 런타임 메타데이터(정보) 객체. 리플렉션, 객체 생성, 타입 검사에 사용됩니다.- CDO: 클래스의 기본값을 담고 있는 실제 인스턴스. 각
UClass
마다 하나씩 존재하며, 새 객체를 생성할 때 초기값을 제공하는 템플릿 역할을 합니다.
UClass
와 CDO는 언리얼 엔진의 강력한 기능들(블루프린트, 에디터, 네트워크 등)을 가능하게 하는 핵심 요소입니다. 이 개념을 이해하면 언리얼 엔진의 작동 방식을 더 깊이 이해하는 데 도움이 될 것입니다.
728x90
'언리얼엔진' 카테고리의 다른 글
언리얼엔진 Composition 사용법 (0) | 2025.04.07 |
---|---|
언리얼 엔진에 인터페이스란 (0) | 2025.04.07 |
언리얼엔진 멀티플레이어 세션 관리 상세 설명 (0) | 2025.03.31 |
언리얼엔진 리플렉션 시스템 이란 (0) | 2025.03.30 |
언리얼엔진 GENERATED_BODY() (0) | 2025.03.29 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 코프링
- unreal engjin
- JVM
- Java
- generated_body()
- JAVA 프로그래밍
- 코틀린
- First-class citizen
- 타입 안전성
- 스브링부트
- model context protocol
- react.js
- vite
- Heap Area
- 언리얼엔진5
- 도커
- 언리얼엔진
- 카프카 개념
- 자바
- springai
- method Area
- MCP
- cqrs
- Stack Area
- ai통합
- 스프링부트
- redis
- 일급 객체
- RESTfull
- 디자인패턴
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
글 보관함