본문으로 건너뛰기

안동민 개발노트

본문 시작

AActor와 UObject의 차이점

UObject와 AActor의 수명·월드 배치·컴포넌트·복제 차이를 비교하고 생성 API를 올바르게 선택합니다.

지난 절에서 리플렉션 시스템과 핵심 매크로를 익혔다면, 이제 객체 시스템의 뼈대로 내려가야 합니다.

이번 절은 언리얼 C++에서 가장 자주 만나는 기본 클래스, UObjectAActor를 비교합니다.

두 클래스의 경계를 명확히 이해해야 설계 실수를 줄일 수 있습니다.

핵심 비교 흐름: UObject 기반 공통 엔진 기능 위에 AActor가 월드 배치/트랜스폼/컴포넌트/복제 기능을 확장하고, 생성 API도 NewObject<>SpawnActor<>로 나뉩니다.

UObject와 AActor 구분

두 클래스는 상속 관계지만 설계 기준이 다르다. 월드 위치와 컴포넌트가 필요하면 AActor, 데이터와 엔진 관리가 필요하면 UObject가 출발점이다.

  1. UObject

    언리얼 객체 시스템에 들어가는 가장 기본 단위다. 월드에 직접 배치되지는 않는다. 관리 GC, 직렬화, 리플렉션, 에디터 노출을 사용할 수 있다. 용도 데이터 모델, 관리자 객체, 에셋 기반 정보에 적합하다. 생성 보통 NewObject<>로 만들고 UPROPERTY 참조를 유지한다.

  2. AActor

    UObject를 기반으로 월드 배치, 트랜스폼, 컴포넌트, 복제를 확장한 클래스다. 공간 위치, 회전, 크기를 가지고 레벨에 놓일 수 있다. 구성 StaticMesh, Collision, Movement 같은 컴포넌트를 붙인다. 생성 월드 컨텍스트에서 SpawnActor<>로 만들고 Destroy로 정리한다.


UObject: 언리얼 객체 시스템의 기반

먼저 UObject를 정리하겠습니다.

UObject는 언리얼 엔진의 모든 객체 지향 프로그래밍의 가장 기본적인 조상 클래스입니다.

언리얼 엔진에서 객체라고 불리는 거의 모든 것(액터, 컴포넌트, 에셋, 게임 모드 등)은 직간접적으로 UObject를 상속받습니다.

UObject가 담당하는 핵심적인 역할들은 다음과 같습니다.

  • 리플렉션 시스템 통합: UObject는 앞서 배운 UCLASS, UPROPERTY, UFUNCTION 매크로를 통해 언리얼 엔진의 리플렉션 시스템에 통합됩니다. 덕분에 UObject를 상속받은 모든 클래스는 에디터에서 속성을 조작하고, 블루프린트와 연동되며, 저장 및 로드될 수 있습니다.
  • 가비지 컬렉션(Garbage Collection) 관리: UObject는 언리얼의 가비지 컬렉터가 수명 주기를 관리합니다. 참조가 끊긴 객체는 엔진이 자동으로 회수하므로 메모리 누수 위험을 줄일 수 있고, 개발자는 수동 해제 부담을 크게 덜 수 있습니다.
  • 직렬화(Serialization): UObject는 자신과 자신의 속성들을 저장하고 불러올 수 있는 직렬화 기능을 제공합니다. 이는 게임 상태를 저장하거나, 네트워크를 통해 객체 데이터를 전송할 때 매우 유용합니다.
  • 에디터 통합: UObject 기반의 객체들은 언리얼 에디터에 통합되어 콘텐츠 브라우저에 표시되거나, 디테일 패널에서 속성을 편집할 수 있게 됩니다.
  • 이름 관리 및 참조: UObject는 엔진 내에서 고유한 이름을 가질 수 있으며, 다른 UObject들을 강력하게 참조할 수 있는 메커니즘을 제공합니다.

간단히 말해, UObject는 언리얼 엔진의 스마트한 객체 시스템에 편입되어 엔진의 다양한 관리 기능(메모리, 직렬화, 반사 등)의 혜택을 받을 수 있도록 해주는 최소 단위의 클래스입니다.

여러분이 만드는 커스텀 데이터 구조체나 관리자 클래스 등이 게임 월드에 직접 배치되지 않으면서도 엔진의 관리가 필요한 경우, UObject를 상속받아 사용하게 됩니다.


AActor: 월드에 존재할 수 있는 모든 것

그렇다면 AActor는 무엇일까요?

AActor는 이름에서 알 수 있듯이, 언리얼 엔진의 3D 게임 월드(Level)에 배치될 수 있는 모든 객체의 기본 클래스입니다.

즉, 여러분이 게임 화면에서 보거나 상호작용할 수 있는 거의 모든 것들(캐릭터, 카메라, 라이트, 스폰 지점, 트리, 건물 등)은 AActor를 상속받습니다.

AActorUObject를 상속받습니다.

이는 AActorUObject의 모든 기능을 그대로 물려받는다는 의미입니다.

즉, AActor도 가비지 컬렉션의 대상이 되고, 직렬화되며, 에디터에 노출됩니다.

하지만 AActorUObject에는 없는 추가적인 중요한 기능들을 제공합니다.

  • 변환(Transform) 정보: AActor는 3D 월드에서 자신의 위치(Location), 회전(Rotation), 크기(Scale) 정보를 가집니다. 이 정보들을 통해 액터가 3D 공간의 어디에 어떻게 존재하는지 정의됩니다.
  • 컴포넌트(Components) 컨테이너: AActor는 여러 UActorComponent를 부착해 기능을 확장하는 컨테이너입니다. StaticMeshComponent(시각 요소), CapsuleComponent(충돌), MovementComponent(이동)처럼 역할을 분리해 조합하면 복잡한 액터도 구조적으로 관리할 수 있습니다.
  • 수명 주기 관리: AActorBeginPlay(), Tick(), EndPlay() 등 게임 월드 내에서의 특정 이벤트 발생 시 호출되는 중요한 수명 주기 함수들을 가집니다. 여러분은 이 함수들을 오버라이드(Override)하여 액터의 동작을 정의하게 됩니다.
  • 네트워크 복제(Networking Replication): 멀티플레이어 게임을 만들 때, AActor는 네트워크를 통해 자신의 상태를 클라이언트들에게 복제하는 기능을 제공합니다.
  • 콜리전(Collision) 및 물리 시뮬레이션: 액터는 자체적으로 또는 컴포넌트를 통해 다른 액터들과의 충돌을 감지하고, 물리 시뮬레이션에 참여할 수 있습니다.

핵심 차이점 요약: 월드에 존재하느냐?

Transform과 월드 수명주기가 필요하면 AActor, 데이터면 UObject를 고른다

클래스 선택은 편한 이름보다 월드 존재, 생성 API, 참조 보관 방식으로 결정한다.

판단 질문AActor 쪽 신호UObject 쪽 신호
월드 존재레벨에 놓이거나 SpawnActor로 생성된다위치가 필요 없는 데이터와 전략 객체다
기능 요구Transform, Tick, Collision, Replication이 필요하다직렬화와 GC 추적만 있으면 충분하다
생성 APIUWorld::SpawnActor 흐름을 따른다NewObject<T>(Outer)로 만든다
수명 관리Destroy와 EndPlay를 고려한다UPROPERTY 참조와 Outer가 생존을 결정한다

가장 핵심적인 차이점을 한 문장으로 요약하자면 이렇습니다.

  • UObject: 언리얼 엔진의 객체 시스템에 편입되어 엔진의 관리를 받는 일반적인 객체입니다. 하지만 3D 월드에 직접적으로 배치되거나 시각적으로 나타나지 않습니다.
  • AActor: UObject를 상속받아 UObject의 모든 기능을 가지면서, 3D 게임 월드에 배치될 수 있는 특별한 객체입니다. 위치, 회전, 스케일과 같은 변환 정보를 가지며, 컴포넌트들을 통해 다양한 시각적/물리적/논리적 기능을 수행합니다.
특징UObjectAActor
기본 조상언리얼 엔진 모든 객체의 최상위 클래스UObject를 상속받음
월드 존재3D 월드에 직접 배치되지 않음3D 월드에 직접 배치 가능 (위치, 회전, 스케일 가짐)
용도데이터 컨테이너, 관리자, 에셋 등게임 월드 내의 플레이어, 적, 환경 오브젝트, 라이트 등
컴포넌트가질 수 없음 (정확히는 UActorComponent 아님)UActorComponent를 상속받는 컴포넌트들을 가질 수 있음
수명 주기주로 가비지 컬렉터에 의해 관리BeginPlay, Tick, EndPlay 등 월드 이벤트와 연동됨

UE5 기준 생성/수명주기 판단

실무에서는 무엇을 상속받을지와 함께 어떻게 생성하고 언제 정리되는지를 같이 판단해야 합니다.

  • UObject 생성: NewObject<>()를 사용합니다. UPROPERTY 또는 TObjectPtr로 참조를 유지하지 않으면 GC 대상이 될 수 있습니다.
  • 컴포넌트 생성: 생성자에서는 CreateDefaultSubobject<>(), 런타임 동적 생성은 NewObject<>()RegisterComponent() 흐름을 사용합니다.
  • AActor 생성: 반드시 월드 컨텍스트에서 SpawnActor<>()로 생성합니다. Destroy() 호출 이후에는 참조가 유효한지 항상 확인해야 합니다.

아래 흐름은 클래스 선택, 생성 API, 소유/참조 방식, 종료 시점을 한 번에 묶어 실무 판단 순서로 정리한 것입니다.

UObject, Component, Actor는 존재 위치와 생성 API가 다르다

월드에 있는지, 액터에 붙는지, 순수 데이터인지 나누면 소유자와 참조 유지 방식이 정리된다.

타입생성 위치수명 판단
UObjectNewObject로 만들고 Outer와 UPROPERTY 참조가 붙잡는다참조가 끊기면 GC 후보가 된다
Default Component생성자에서 CreateDefaultSubobject로 만든다액터와 함께 태어나고 사라진다
Runtime ComponentNewObject 후 RegisterComponent로 붙인다소유 Actor가 등록과 해제를 책임진다
AActorWorld 컨텍스트에서 SpawnActor로 만든다Destroy, BeginPlay, Tick, Replication을 고려한다

UObject 계열을 C++ 포인터로만 들고 있으면 언젠가 참조가 끊길 수 있으므로, 오래 유지할 참조는 UPROPERTY 기반으로 선언하는 습관이 안전합니다.

자주 발생하는 오해

  • UObject도 월드 위치를 가진다: 아닙니다. 월드 트랜스폼이 필요하면 AActor 또는 USceneComponent 기반으로 설계해야 합니다.
  • AActordelete로 정리한다: 아닙니다. 언리얼 수명주기(Destroy, GC)에 맞춰 정리해야 하며 수동 delete는 사용하지 않습니다.
  • 복제는 아무 클래스에서나 자동 동작한다: 네트워크 복제는 기본적으로 AActor(및 관련 컴포넌트) 경로에서 설계하는 것이 표준입니다.

클래스 선택은 상속 이름만 고르는 문제가 아니라 월드 존재, 생성 API, 참조 유지, 정리 방식까지 함께 결정하는 설계 판단입니다.

객체 선택은 월드 존재와 소유자 기준으로 결정한다

UObject, Component, Actor는 모두 엔진 객체지만 생성 API, 월드 배치, 수명 종료 신호가 다릅니다.

생성 API와 수명 관리 기준
선택지생성 API쓸 때수명 확인
UObject 데이터 객체NewObject월드 트랜스폼이 필요 없는 인벤토리, 설정, 런타임 데이터참조 추적 소유자와 반사 참조로 정리 경로 유지
Component 액터 구성품CreateDefaultSubobjectMesh, Collision, Camera처럼 액터와 함께 움직이는 기능소유 Actor가 생성과 파괴 흐름을 이끕니다.
Actor 월드 배치 대상SpawnActor위치, 회전, 충돌, BeginPlay, Replication이 필요할 때Destroy 흐름 파괴 요청 뒤 유효성과 종료 신호 확인
Subsystem 전역 서비스엔진 수명에 따른 자동 생성월드, 게임 인스턴스, 에디터 범위의 공용 기능World, GameInstance, Engine 중 어느 범위인지 먼저 고릅니다.

언제 무엇을 사용할까?

  • AActor를 상속받을 때
    • 게임 월드에 시각적으로 배치되어야 하는 오브젝트 (예: 캐릭터, 건물, 무기, 차량, 조명).
    • 3D 공간에서 위치, 회전, 스케일 정보를 가져야 하는 오브젝트.
    • 다른 컴포넌트를 부착하여 복합적인 기능을 수행해야 하는 오브젝트.
    • 특정 게임 이벤트(예: 충돌, 트리거)에 반응해야 하는 오브젝트.
  • UObject를 상속받을 때
    • 게임 월드에 직접 배치될 필요는 없지만, 엔진의 가비지 컬렉션이나 직렬화의 혜택을 받고 싶은 데이터 컨테이너.
    • 특정 시스템의 관리자 클래스 (예: 인벤토리 관리자, 퀘스트 관리자).
    • 특정 UI 위젯의 데이터 모델.
    • 블루프린트에서 접근하고 싶은 커스텀 데이터 구조체.
    • UActorComponent를 상속받지 않는 순수 논리적 컴포넌트.

언리얼 엔진 프로젝트에서는 월드 배치 여부, 컴포넌트 소유 여부, 리플렉션 필요성에 따라 기본 클래스를 선택해야 합니다.

다음 절에서는 AActor를 상속받는 첫 C++ 클래스를 생성하고 코드로 확인합니다.

AActor와 UObject 선택 기준

두 타입은 모두 엔진 객체 체계에 속하지만, 월드 배치 여부와 컴포넌트 소유 여부가 선택 기준을 크게 가릅니다.

AActor/UObject 선택 기준

월드에 존재해야 하는 책임인지, 데이터와 서비스처럼 독립적으로 관리할 책임인지 먼저 나눕니다.

  1. AActor

    월드에 배치되고 Transform, Tick, Replication 같은 런타임 맥락이 필요할 때 씁니다.

  2. Component

    Actor에 붙는 렌더링, 충돌, 입력 보조 기능은 컴포넌트로 나눕니다.

  3. UObject

    에셋 데이터, 설정, 헬퍼 객체처럼 월드 위치가 필요 없는 책임에 적합합니다.

  4. 검산

    레벨에 놓을 수 있어야 하는지, 가비지 컬렉션 수명만 필요한지 질문합니다.

월드에 존재해야 하는지, 어떤 생성 API를 써야 하는지, 참조를 어디에 보관해야 하는지까지 한 번에 정리합니다.

데이터, 월드 객체, 컴포넌트, 참조 보관 방식을 함께 고른다

어디에 존재하고 누가 오래 붙잡는지 답하면 타입 선택이 단순해진다.

선택지맞는 경우같이 확인할 것
UObject위치가 필요 없고 GC와 직렬화만 필요하다Outer와 UPROPERTY 참조
AActor월드에 배치되거나 스폰되어 Transform이 필요하다SpawnActor, Destroy, Replication
Component액터의 기능 일부로 등록되어야 한다소유 Actor와 등록 시점
ReferenceGC 대상 객체를 안전하게 붙잡아야 한다TObjectPtr, UPROPERTY, 수명 주체