icon안동민 개발노트

언리얼 오브젝트 모델 소개


 언리얼 오브젝트 모델은 언리얼 엔진의 핵심 아키텍처로, 게임 개발에 필요한 다양한 기능과 최적화를 제공합니다.

 이 모델의 중심에는 UObject 클래스가 있으며, 이를 기반으로 다양한 게임 오브젝트들이 구현됩니다.

UObject 클래스

 UObject는 언리얼 엔진의 모든 오브젝트의 기본 클래스입니다.

 특징 및 기능

  1. 가비지 컬렉션 : 자동 메모리 관리
  2. 리플렉션 : 런타임에 객체의 속성과 메서드에 접근
  3. 시리얼라이제이션 : 객체 상태의 저장 및 로드
  4. 네트워크 리플리케이션 : 멀티플레이어 게임에서 객체 동기화

 예시

UCLASS()
class UMyObject : public UObject
{
    GENERATED_BODY()
 
public:
    UPROPERTY()
    int32 MyIntProperty;
 
    UFUNCTION()
    void MyFunction() { /* ... */ }
};

언리얼 오브젝트 계층 구조

 UObject를 기반으로 다양한 특화된 클래스들이 존재합니다.

  1. AActor : 게임 월드에 배치할 수 있는 오브젝트
  2. UActorComponent : Actor에 부착되어 기능을 제공하는 컴포넌트
  3. UStruct : 데이터만을 포함하는 구조체
  4. 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);
    }
};

언리얼 오브젝트 생성 및 관리

생성 방법

  1. NewObject<T>() : 일반적인 UObject 생성
  2. SpawnActor<T>() : Actor 생성 및 게임 월드에 배치
  3. CreateDefaultSubobject<T>() : 컴포넌트 생성

 예시

UMyObject* Obj = NewObject<UMyObject>();
AMyActor* Actor = GetWorld()->SpawnActor<AMyActor>(AMyActor::StaticClass(), Location, Rotation);

생명주기

  1. 생성 (Construction)
  2. 초기화 (Initialization)
  3. 실행 (Runtime)
  4. 소멸 (Destruction)

 AActor의 경우 추가적인 이벤트가 있습니다.

  • BeginPlay() : 게임 플레이 시작 시 호출
  • Tick() : 매 프레임마다 호출
  • EndPlay() : 액터가 제거될 때 호출

메모리 관리 특성

  1. 가비지 컬렉션 : 자동으로 더 이상 참조되지 않는 객체 정리
  2. 참조 카운팅 : 일부 객체(예 : UActorComponent)는 참조 카운팅 사용
  3. 명시적 삭제 : Destroy() 함수를 통한 액터 삭제

 주의 : UObject 파생 클래스는 일반적으로 new/delete 연산자로 직접 생성/삭제하지 않습니다.

Best Practices

  1. UPROPERTY 매크로 활용 : 가비지 컬렉션과 리플렉션을 위해 중요
  2. 인터페이스 사용 : 다중 상속 대신 UInterface 활용
  3. 컴포넌트 기반 설계 : 기능을 컴포넌트로 분리하여 재사용성 높이기
  4. 적절한 기본 클래스 선택 : 목적에 맞는 가장 가까운 기본 클래스 선택 (예 : 게임 로직을 위한 AActor, UI를 위한 UUserWidget)

주의사항

  1. 순환 참조 피하기 : 가비지 컬렉션 문제 발생 가능
  2. 대량의 UObject 생성 주의 : 가비지 컬렉션 부하 증가
  3. 스레드 안전성 : UObject는 기본적으로 스레드 안전하지 않음
  4. 성능 고려 : 리플렉션과 가비지 컬렉션은 오버헤드를 동반할 수 있음

결론

 언리얼 오브젝트 모델은 언리얼 엔진의 강력한 기능을 제공하는 핵심 요소입니다. 가비지 컬렉션, 리플렉션, 시리얼라이제이션, 네트워크 리플리케이션 등의 기능은 게임 개발을 크게 단순화하고 효율화합니다. 이 모델을 효과적으로 활용하면 확장 가능하고 유지보수가 용이한 게임 코드를 작성할 수 있습니다.

 그러나 이러한 기능들은 때로 성능 오버헤드를 동반할 수 있으므로, 대규모 프로젝트에서는 신중한 설계와 최적화가 필요합니다. 언리얼 오브젝트 모델의 특성을 잘 이해하고, 프로젝트의 요구사항에 맞게 적절히 활용하는 것이 중요합니다. 특히 메모리 관리, 참조 관계 설계, 그리고 성능 최적화에 주의를 기울여야 합니다.

 언리얼 오브젝트 모델은 학습 곡선이 있을 수 있지만, 이를 마스터하면 언리얼 엔진의 강력한 기능을 최대한 활용하여 효율적이고 견고한 게임을 개발할 수 있습니다.