UPROPERTY()는 C++의 함수처럼 오버로딩(Overloading) 되는 것이 아니라, 언리얼 헤더 툴(Unreal Header Tool, UHT)이 코드를 분석할 때 사용하는 지정자(Specifier)들의 조합을 인자로 받는다.
이 지정자들은 변수가 에디터에 어떻게 노출될지, 블루프린트에서 어떻게 접근할지, 메모리 관리(GC)와 네트워크에서 어떻게 처리될지를 결정한다.
1. 에디터 노출 및 편집 권한 (Editor Accessibility)
변수를 에디터의 '디테일 패널'에서 어떻게 다룰지 결정한다. 가장 헷갈리기 쉬운 부분이므로 명확히 구분해야 한다.

⚠️ 주의 (컴포넌트 포인터): 컴포넌트 포인터(UStaticMeshComponent* 등) 선언 시에는 절대 EditAnywhere를 쓰면 안된다. 대신 VisibleAnywhere를 사용해야 한다. EditAnywhere를 쓰면 에디터에서 컴포넌트 참조 자체를 null로 만들어버릴 위험이 있다. VisibleAnywhere를 써도 컴포넌트 내부의 변수(Mesh, Material 등)는 수정 가능.
2. 블루프린트 접근성 (Blueprint Accessibility)
C++ 변수를 블루프린트 그래프에서 Get/Set 할 수 있는지 결정한다.
BlueprintReadOnly: 블루프린트에서 값을 읽을 수만 있다 (Get 노드).BlueprintReadWrite: 블루프린트에서 값을 읽고 쓸 수 있다 (Get/Set 노드).BlueprintGetter / BlueprintSetter: 캡슐화를 위해 직접 접근 대신 특정 Accessor 함수를 사용하도록 강제다.
3. 카테고리 및 메타데이터 (Category & Meta)
깔끔한 에디터 정리를 위해 필수적으로 사용해야 한다.
Category = "Name": 디테일 패널에서 변수가 표시될 그룹을 지정. 계층 구조는|로 구분한다. (예:Category = "Combat|Stats")meta = (...): 에디터 동작을 제어하는 추가 속성.ClampMin = "0.0",ClampMax = "100.0": 입력 값의 범위를 제한.UIMin,UIMax: 슬라이더의 범위만 제한하고, 직접 입력은 허용.DisplayName = "Custom Name": 변수명 대신 보여줄 이름.AllowPrivateAccess = "true":private변수이지만 에디터/블루프린트 노출을 허용할 때 사용. (캡슐화 유지에 추천).
4. 메모리 및 네트워크 (Memory & Network)
Transient: 이 변수를 디스크에 저장(직렬화)하지 않는다. 게임 실행 중에만 잠시 사용하는 값(예: 현재 프레임의 계산 캐시)에 사용.Replicated: 네트워크 멀티플레이어 게임에서 서버의 값을 클라이언트로 동기화. (추가로로GetLifetimeReplicatedProps설정 필요)ReplicatedUsing = "OnRep_Function": 값이 변경될 때마다 특정 함수(OnRep_Function)가 클라이언트에서 자동 실행되게 한다. (UI 갱신 등에 필수)Instanced: 객체 참조 시, 원본을 참조하는 것이 아니라 복제된 고유 인스턴스를 생성하여 할당. (인벤토리 아이템, 스킬 시스템의 개별 속성 구현 시 매우 유용)
5. UE5 실전 코드 예시 (Best Practices)
아래 코드는 UE5 스타일(TObjectPtr 사용 등)을 적용한 사례.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
UCLASS()
class MYGAME_API AMyActor : public AActor
{
GENERATED_BODY()
public:
AMyActor();
protected:
// [UE5 권장] 원시 포인터 대신 TObjectPtr 사용 (에디터 빌드 시 Lazy Loading 지원)
// 컴포넌트는 포인터 참조 자체를 바꾸지 않으므로 VisibleAnywhere 권장
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
TObjectPtr<class UStaticMeshComponent> MeshComp;
// 기획자가 자유롭게 수정 가능, 값의 범위(0~100) 강제
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats", meta = (ClampMin = "0.0", ClampMax = "100.0"))
float Health;
// 런타임에만 계산되는 값. 저장되지 않음. 디버깅용으로 에디터에서 값 확인만 가능
UPROPERTY(VisibleInstanceOnly, Transient, Category = "Stats|Debug")
float CurrentStamina;
private:
// Private이지만 블루프린트와 에디터에서 접근 허용 (캡슐화 유지)
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Config", meta = (AllowPrivateAccess = "true"))
float BaseDamage;
};
💡 핵심 요약 및 팁
- Garbage Collection(GC):
UPROPERTY()매크로가 붙은UObject*(또는TObjectPtr) 변수는 자동으로 레퍼런스 카운팅이 되어 GC에 의해 삭제되지 않는다. 반대로,UPROPERTY()없이UObject*를 멤버 변수로 들고 있으면 예고 없이 메모리가 해제되어 크래시(Dangling Pointer)가 발생할 수 있다. - UE5의
TObjectPtr: UE5부터는 헤더 파일의 멤버 변수 선언 시Raw Pointer (\*)대신TObjectPtr를 사용하는 것을 강력히 권장한다. 이는 에디터 성능 최적화 및 Optional Loading을 위함이며,.cpp\구현부에서는 기존 포인터처럼 사용하면 된다. - 하이브리드 접근: 복잡한 로직은 C++로 짜고,
BlueprintReadWrite나EditDefaultsOnly를 통해 디자이너가 수치만 조절하게 하는 것이 가장 효율적인 패턴이다.
'프로그래밍 > Unreal Engine 5' 카테고리의 다른 글
| [Unreal Engine 5] 충돌처리를 위해 바인딩(Binding)을 하는 이유 (0) | 2026.01.23 |
|---|---|
| [Unreal Engine 5] TSubclassOf<T> (0) | 2026.01.16 |
| [Unreal Engine 5] 액터의 라이프 사이클 (2) | 2026.01.09 |
| [Unreal Engine 5] 언리얼 엔진 5의 스마트 포인터 (1) | 2026.01.08 |
| [Unreal Engine 5] Transform Direction (0) | 2025.12.04 |