언리얼 오브젝트 모델 소개
언리얼 오브젝트 모델은 언리얼 엔진의 핵심 아키텍처로, 게임 개발에 필요한 다양한 기능과 최적화를 제공합니다.
이 모델의 중심에는 UObject 클래스가 있으며, 이를 기반으로 다양한 게임 오브젝트들이 구현됩니다.
UObject 클래스
UObject는 언리얼 엔진의 모든 오브젝트의 기본 클래스입니다.
특징 및 기능
- 가비지 컬렉션 : 자동 메모리 관리
- 리플렉션 : 런타임에 객체의 속성과 메서드에 접근
- 시리얼라이제이션 : 객체 상태의 저장 및 로드
- 네트워크 리플리케이션 : 멀티플레이어 게임에서 객체 동기화
예시
UCLASS()
class UMyObject : public UObject
{
GENERATED_BODY()
public:
UPROPERTY()
int32 MyIntProperty;
UFUNCTION()
void MyFunction() { /* ... */ }
};
언리얼 오브젝트 계층 구조
UObject를 기반으로 다양한 특화된 클래스들이 존재합니다.
- AActor : 게임 월드에 배치할 수 있는 오브젝트
- UActorComponent : Actor에 부착되어 기능을 제공하는 컴포넌트
- UStruct : 데이터만을 포함하는 구조체
- UInterface : 인터페이스 정의를 위한 클래스
계층 구조 예시
UObject
├── AActor
│ ├── APawn
│ │ └── ACharacter
│ └── APlayerController
├── UActorComponent
│ ├── USceneComponent
│ │ └── UPrimitiveComponent
│ │ └── UStaticMeshComponent
│ └── UMovementComponent
└── UStruct
└── FVector
주요 기능 상세 설명
1. 가비지 컬렉션
언리얼 엔진은 자동으로 더 이상 사용되지 않는 UObject 인스턴스를 정리합니다.
UMyObject* MyObj = NewObject<UMyObject>();
// MyObj는 가비지 컬렉션에 의해 자동으로 정리됩니다.
주의 : 순환 참조를 피해야 합니다. 필요한 경우 약한 포인터(TWeakObjectPtr)를 사용하세요.
2. 리플렉션
리플렉션 시스템을 통해 런타임에 객체의 속성과 함수에 접근할 수 있습니다.
UClass* MyClass = UMyObject::StaticClass();
for (TFieldIterator<FProperty> PropIt(MyClass); PropIt; ++PropIt)
{
FProperty* Property = *PropIt;
UE_LOG(LogTemp, Log, TEXT("Property: %s"), *Property->GetName());
}
이 기능은 에디터 툴, 직렬화, 네트워크 복제 등에 광범위하게 사용됩니다.
3. 시리얼라이제이션
UObject는 자동으로 시리얼라이제이션을 지원합니다.
FMemoryWriter MemWriter(Data);
UMyObject* MyObj = NewObject<UMyObject>();
MyObj->Serialize(MemWriter);
FMemoryReader MemReader(Data);
UMyObject* LoadedObj = NewObject<UMyObject>();
LoadedObj->Serialize(MemReader);
이를 통해 게임 상태 저장 및 로드, 네트워크 전송 등이 간편해집니다.
4. 네트워크 리플리케이션
멀티플레이어 게임에서 객체의 상태를 자동으로 동기화할 수 있습니다.
UCLASS(Replicated)
class AMyActor : public AActor
{
GENERATED_BODY()
UPROPERTY(Replicated)
float Health;
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMyActor, Health);
}
};
언리얼 오브젝트 생성 및 관리
생성 방법
NewObject<T>()
: 일반적인 UObject 생성SpawnActor<T>()
: Actor 생성 및 게임 월드에 배치CreateDefaultSubobject<T>()
: 컴포넌트 생성
예시
UMyObject* Obj = NewObject<UMyObject>();
AMyActor* Actor = GetWorld()->SpawnActor<AMyActor>(AMyActor::StaticClass(), Location, Rotation);
생명주기
- 생성 (Construction)
- 초기화 (Initialization)
- 실행 (Runtime)
- 소멸 (Destruction)
AActor의 경우 추가적인 이벤트가 있습니다.
- BeginPlay() : 게임 플레이 시작 시 호출
- Tick() : 매 프레임마다 호출
- EndPlay() : 액터가 제거될 때 호출
메모리 관리 특성
- 가비지 컬렉션 : 자동으로 더 이상 참조되지 않는 객체 정리
- 참조 카운팅 : 일부 객체(예 : UActorComponent)는 참조 카운팅 사용
- 명시적 삭제 : Destroy() 함수를 통한 액터 삭제
주의 : UObject 파생 클래스는 일반적으로 new/delete 연산자로 직접 생성/삭제하지 않습니다.
Best Practices
- UPROPERTY 매크로 활용 : 가비지 컬렉션과 리플렉션을 위해 중요
- 인터페이스 사용 : 다중 상속 대신 UInterface 활용
- 컴포넌트 기반 설계 : 기능을 컴포넌트로 분리하여 재사용성 높이기
- 적절한 기본 클래스 선택 : 목적에 맞는 가장 가까운 기본 클래스 선택 (예 : 게임 로직을 위한 AActor, UI를 위한 UUserWidget)
주의사항
- 순환 참조 피하기 : 가비지 컬렉션 문제 발생 가능
- 대량의 UObject 생성 주의 : 가비지 컬렉션 부하 증가
- 스레드 안전성 : UObject는 기본적으로 스레드 안전하지 않음
- 성능 고려 : 리플렉션과 가비지 컬렉션은 오버헤드를 동반할 수 있음
결론
언리얼 오브젝트 모델은 언리얼 엔진의 강력한 기능을 제공하는 핵심 요소입니다.
가비지 컬렉션, 리플렉션, 시리얼라이제이션, 네트워크 리플리케이션 등의 기능은 게임 개발을 크게 단순화하고 효율화합니다.