1. UPROPERTY
: 언리얼 엔진에서 UPROPERTY는 C++ 클래스의 멤버 변수를 언리얼 엔진의 시스템(리플렉션 시스템)에 등록하는 매크로이다.
C++ 변수 위에 UPROPERTY()를 붙이지 않으면, 그 변수는 일반적인 C++ 변수일 뿐이며 언리얼 엔진의 특수 기능들을 전혀 사용할 수 없다.
- UPROPERTY가 제공하는 핵심 기능
: UPROPERTY를 사용하면 언리얼 엔진이 다음과 같은 기능들을 자동으로 처리해 준다.
- 가비지 컬렉션 (메모리 관리)
: 언리얼 엔진이 변수의 참조 상태를 추적한다.
더 이상 사용되지 않는 객체(Object)를 자동으로 메모리에서 해제하여 메모리 누수를 방지한다.
- 디테일 패널 노출
: 에디터의 '디테일(Details)' 창에 변수를 표시하여, 개발자가 코드를 수정하지 않고도 에디터에서 직접 값을 변경할 수 있다.
- 네트워크 복제 (Replication)
: 멀티플레이어 게임을 만들 때, 서버의 변수 값이 변경되면 클라이언트를 자동으로 동기화되도록 설정할 수 있다.
- 직렬화 (Serialization)
: 게임을 저장하거나 불러올 때 변수의 값을 자동으로 파일에 저장하고 복구할 수 있게 한다.
- 가장 자주 쓰이는 지정자 (Specifiers)
: UPROPERTY() 괄호 안에는 다양한 지정자를 넣어 변수의 성격과 권한을 세부적으로 제어할 수 있다.
1) 에디터 노출 관련 (디테일 패널)
: 에디터에서 변수를 어떻게 보여주고 수정하게 할지 결정한다.
- EditAnywhere
: 에디터의 디테일 패널과 블루프린트 에셋 창 양쪽 모두에서 값을 수정할 수 있다.
- EditDefaultOnly
: 블루프린트 에셋(원형) 창에서만 수정할 수 있고, 레벨에 배치된 개별 액터의 디테일 패널에서는 수정할 수 없다.
- EditInstanceOnly
: 레벨에 배치된 개별 액터의 디테일 패널에서만 수정할 수 있고, 블루프린트 에셋 창에서는 수정할 수 없다.
- VisibileAnywhere / VisibleDefaultOnly / VisibleInstanceOnly
: 위와 규칙은 같지만, 값을 수정할 수는 없고 디테일 패널에서 보기만 가능(읽기 전용)하게 만든다.
2) 블루프린트 연동 관련
: 블루프린트 그래프에서 이 변수를 어떻게 다룰지 결정한다.
- BlueprintReadOnly
: 블루프린트에서 이 변수의 값을 가져올 수만 있다. (Get 노드만 사용 가능)
- BlueprintReadWrite
: 블루프린트에서 이 변수의 값을 가져오거나 변경할 수 있다. (Get / Set 노드 모두 사용 가능)
3) 카테고리 지정
- Category = "이름"
: 디테일 패널이나 블루프린트에서 변수들을 그룹화하여 보기 좋게 정리해준다.
계층 구조가 필요하다면 Category = "Combat|Weapon" 처럼 폰트 ( | ) 기호를 사용할 수 있다.
* UPROPERTY 사용시 주의할 점
1. 포인터 변수는 필수
: 다른 UObject나 AActor를 가리키는 포인터 변수(AActor* MyTarget; 등)를 선언할 때는 반드시 위에 UPROPERTY()를 붙여주어야 한다.
그렇지 않으면 가비지 컬렉터가 해당 객체를 메모리에서 지워버려, 나중에 댕글링 포인터(Dangling Pointer)로 인한 크래시가 발생할 수 있다.
2. 기본 자료형 초기화
: C++ 특성상 int32, float, bool 같은 기본 자료형은 선언만 하면 쓰레기 값이 들어갈 수 있으므로, 생성자나 선언부에서 꼭 초기화를 해주는 것이 좋다. (예 : float Health = 100.0f;)
2. UObject
: 언리얼 엔진에서 UObject는 엔진 프레임워크의 최상위 루트(Root) 기본 클래스이다.
언리얼 엔진이 제공하는 거의 모든 핵심 기능(메모리 관리, 리플렉션, 블루프린트 연동 등)을 사용할 수 있는 '가장 원초적인 객체' 이다. (예 : 액터나 컴포넌트도 결국 UObject를 상속받아 만들어진 자식이다.)
- UObject 계층 구조 이해하기
: 언리얼 엔진의 오브젝트 구조는 거대한 피라미드 형태를 띠고 있다.
- Object
: 최상위 부모, 데이터와 논리 구조를 가질 수 있지만, 월드(게임 화면)에 직접 배치할 수는 없다. (트랜스폼 값이 없다.)
- AActor
: UObject를 상속받아 만들어진 클래스, 레벨(월드)에 배치할 수 있는 최소 단위이다.
위치 값을 가지며, 게임 안에서 눈에 보이거나 물리적인 상호작용을 할 수 있다.
- UActorComponent
: 액터에 부착되어 특정 기능(외형 렌더링, 무브먼트, 오디오 재생 등)을 담당하는 부품이다.
이것 역시 UObject를 상속받았다.
- UObject가 제공하는 핵심 시스템 (존재 이유)
: 표준 C++ 클래스를 쓰지 않고 굳이 UObject를 상속받아 사용하는 이유는 언리얼 엔진이 자랑하는 오브젝트 처리 시스템을 그대로 이용할 수 있기 때문이다.
1. 가비지 컬렉션 (Garbage Collection)
2. 리플렉션 시스템 (Reflection System)
3. CDO (Class Default Object)
: 언리얼 엔진은 게임이 실행 될 때 각 UObject 클래스마다 단 하나의 '기본 객체(CDO)'를 미리 생성해 둔다.
- 이 클래스로 만들어질 객체들의 '원본 템플릿' 역할을 한다.
- 새로운 객체가 생성 될 때 처음부터 무겁게 초기화 하는 것이 아니라, 이 CDO의 값을 그대로 복사해서 생성하므로 속도가 매우 빠르다.
- C++ 코드에서 UObject 다루기
: UObject는 일반적인 C++ 클래스와 생성 및 관리 방식이 완전히 다르다.
1. 클래스 선언 (접두사 'U')
: 언리얼 엔진 규칙에 따라 UObject를 직접 상속받는 클래스는 이름 앞에 접두사 U를 붙여야 한다. (액터는 A)
2. 객체 생성 (NewObject)
: UObject 기반 클래스는 절대 C++ 표준 방식인 new MyClass() 로 생성하면 안된다.
엔진 시스템에 등록하며 생성해야 하므로 NewObject<T>() 함수를 사용해야 한다.
3. 객체 소멸 (메모리 해제)
: delete NewData; 역시 절대 사용 금지이다.
- UPROPERTY()로 지정된 변수에서 해당 객체의 참조를 끊거나 nullptr을 대입하면, 다음 가비지 컬렉션 주기에 자동으로 메모리가 해제된다.
- 명시적으로 즉시 지우고 싶다면 NewData->MarkAsGarbage(); 를 호출하여 가비지 컬렉터에게 지워달라고 마킹할 수 있다.
* 요약
- 언제 UObject를 직접 상속받아 사용 하는가?
: 게임에 배치될 필요는 없지만(즉, 위치나 외형이 필요 없음), 언리얼의 메모리 관리와 블루프린트 연동이 필요한 순수한 데이터나 논리 시스템을 만들 때 사용한다.
예) 게임의 세이브 데이터 구조체, 아이템 인벤토리의 데이터 시스템, 퀘스트 정보 저장소, 복잡한 스킬의 효과(Buff/Debuff) 게산 로직 등.
'개인 공부' 카테고리의 다른 글
| 06.12 Unreal 키워드로 개념 정리) 직렬화 / GENERATED_BODY (0) | 2026.06.12 |
|---|---|
| 06.10 C/C++ 키워드로 개념 정리) 컴파일 / 게임 프로그래밍 (1) | 2026.06.11 |
| 06.09 Unreal 키워드로 개념 정리) Reflection / Garbage Collector (0) | 2026.06.09 |
| 04.12 액터에 대하여 (0) | 2026.04.12 |
| 04.10 Unreal 설치하기 및 사용감 익히기 (3) | 2026.04.10 |