리플렉션 시스템은 C++ 클래스의 변수 및 함수 정보를 엔진 내부의 메타데이터 형태로 저장해서 에디터나 블루프린트에서 활용할 수 있게 만들어주는 시스템이다.
C++에 있는 여러 멤버 변수, 함수 등을 에디터와 블루프린트에서 직접 설정, 호출이 가능하도록 한다.
매개변수를 코드에서만 변경하는 것이 아니라, 에디터에서 바로 조정 (슬라이더나 숫자 입력)하여 반복 테스트를 빠르게 진행할 수 있다.
언리얼에서 C++로 액터를 생성하면 이미 클래스 선언에 리플렉션 관련 매크로가 포함되어있다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogJin, Warning, All);
UCLASS()
class STUDY5_API AItem : public AActor
{
GENERATED_BODY()
위 코드에서 #include "Item.generated.h"와 UCLASS(), GENERATED_BODY()가 해당된다.
#include "Item.generated.h"
언리얼 엔진이 자동 생성하는 헤더 파일로 클래스의 리플렉션 및 엔진 통합에 필요한 코드가 들어있다.
반드시 헤더 파일의 가장 마지막 #include 구문 아래에 위치해야한다.
UCLASS()
해당 클래스를 언리얼 엔진의 리플렉션 시스템에 등록한다는 의미다.
이 매크로가 있어야 블루프린트 등 에디터에서 이 클래스를 인식하고 사용할 수 있다.
GENERATED_BODY()
언리얼의 코드 생성 도구가 사용하는 코드를 삽입하는 역할을 한다.
클래스 내부에 필요한 리플렉션 정보를 자동으로 생성한다.
UCLASS()와 GENERATED_BODY()는 한 쌍으로 같이 작성을 해줘야만 리플렉션 시스템에 등록이 된다.
UCLASS() 매크로의 주요 지정자
UCLASS()에 옵션을 주지 않으면 블루프린트에서 상속이 가능하고 변수로 참조가 가능한 형태로 등록이 된다.
UCLASS(Blueprintable, BlueprintType) = UCLASS()
블루프린트에서 이 클래스를 상속이 가능하고 변수나 참조로 사용할 수 있다.
UCLASS(NotBlueprintable, BlueprintType) = UCLASS(BlueprintType)
블루프린트에서 이 클래스를 상속이 불가능하고 변수나 참조로 사용할 수 있다.
필요에 따라 이 지정자들을 조합해 클래스가 어떻게 블루프린트와 상호작용해야 할 지 명시할 수 있다.
1. 블루프린트로 Item을 상속받아서 자식 클래스를 만들어보기
C++ Class파일을 우클릭하고 Create Blueprint class based on Item을 누른다
이름을 BP_Item으로 수정 후 블루프린트 폴더에 저장한다.
C++ class파일 Item을 상속받은 BP_Item이 생긴다.
2. C++ 클래스를 블루프린트에서 변수로 참조해보기
블루프린트에서 변수를 하나 생성한다.
변수 타입에서 Item을 검색하고 C++class Item을 클릭한다.
UPROPERTY()
지금까지 클래스를 리플렉션에 등록하는 방법을 알아봤는데 이제 C++에서 선언한 변수들을 리플렉션 시스템에 등록하는 방법을 알아보자.
현재 Item에는 3개의 변수가 선언되어있다. 3개의 변수를 리플렉션 시스템에 등록해서 에디터에서 노출이 되도록 해본다.
UPROPERTY()
float RotationSpeed;
UPROPERTY()
USceneComponent* SceneRoot;
UPROPERTY()
UStaticMeshComponent* StaticMeshComp;
UPROPERTY()를 변수 위에 선언하면 이 변수를 리플렉션 시스템에 등록하는건데 UCLASS()는 인자를 비워도 됐지만 기본적으로 사용이 됐지 UPROPERTY()는 인자를 비우면 등록은 되지만 아무런 효과가 없다.(에디터에서 안보인다)
UPROPERTY(편집 가능 범위 지정자, 블루프린트 접근성 지정자, 카테고리 지정자, 메타 옵션 지정자)로 에디터에서의 표시 여부나 읽기/쓰기 권한 등을 자세하게 설정할 수 있다.
1. 편집 가능 범위 지정자
- VisibleAnywhere: 읽기 전용으로 표시되며, 수정은 불가능
- EditAnywhere: 클래스 기본값, 인스턴스 모두에서 수정 가능
- EditDefaultsOnly: 클래스 기본값에서만 수정 가능
- EditInstanceOnly: 인스턴스에서만 수정 가능
2. Blueprint 접근성 지정자
- BlueprintReadWrite: Blueprint 그래프에서 Getter/Setter로 값을 읽거나 쓸 수 있습니다.
- BlueprintReadOnly: Blueprint 그래프에서 Getter 핀만 노출되어, 읽기만 가능합니다.
3. Category 지정자
- Details 패널에서 이 변수는 “Rotation” 범주(폴더) 아래에 표시됩니다.
- 여러 변수를 비슷한 카테고리에 묶으면, 세부 정보 패널에서 깔끔하게 정리되어 보입니다.
4. 메타 옵션 지정자
- meta=(ClampMin="0.0"): 에디터에서 변수 입력 시 최소값을 제한할 수 있습니다.
- meta=(AllowPrivateAccess="true"): 해당 멤버가 private로 선언되어 있어도, 에디터나 Blueprint에서 접근할 수 있도록 허용합니다.
// Root Scene Component, 에디터에서 볼 수만 있고 수정 불가
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Item|Components")
USceneComponent* SceneRoot;
// Static Mesh, 에디터와 Blueprint에서 수정 가능
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Item|Components")
UStaticMeshComponent* StaticMeshComp;
// 회전 속도, 클래스 기본값만 수정 가능
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Item|Properties")
float RotationSpeed;
UPROPERTY를 위처럼 설정하고 에디터에서 확인해보면 인스턴스 디테일 창에서 StaticMeshComp를 확인할 수 있다
BP_Item의 클래스 디폴트 창에서는 StaticMeshComp와 RotationSpeed 둘 다 확인이 가능하다.
SceneRoot는 확인만 가능하고 수정이 불가하므로 디테일창에 뜨지 않는다.
C++에서 파일 경로를 찾아서 스태틱 메시에 에셋을 넣어줬었는데 이를 블루프린트 에디터에서 수정이 가능하도록 했으니 C++에서 작성한 코드를 지우고 블루프린트에서 적용해보자.
빌드 후 에디터를 실행하여 스태틱 메시를 설정해준다.
스태틱 메시를 똑같이 의자로 바꿔준 후 머티리얼도 의자로 해준다.
C++에서 복잡하게 경로를 알아와서 코드로 붙였었지만 UPROPERTY로 에디터 상에서 접근하게 하 쉽게 스태틱 메시와 머티리얼을 설정할 수 있다.(리플렉션 시스템의 편리함)
UFUNCTION()
마지막으로 함수를 리플렉션 시스템에 등록하는 방법이다. 복잡한 C++ 로직을 Blueprint에서 간단한 노드로 불러와 제어할 수 있으므로 작업 효율이 높아진다.
C++에서 만든 함수를 Blueprint 노드로 노출하고 싶을 때, UFUNCTION() 매크로를 사용한다.
UPROPERTY처럼 인자를 비우면 리플렉션 시스템에 등록만 할 뿐 에디터에서는 안보여서 효과가 없다.
UFUNCTION() 매크로의 주요 지정자
BlueprintCallable
- Blueprint 이벤트 그래프(노드)에서 호출(Execute) 가능한 함수로 만든다.
BlueprintPure
- Getter 역할만 수행합니다. (Exec 핀 없이 Return Value만 노출)
BlueprintImplementableEvent
- 함수의 선언만 C++에 있고, 구현은 블루프린트에서 하도록 합니다.
- C++ 코드에서는 함수 이름만 정의하고, 실제 동작은 Blueprint Event Graph 안에서 이벤트 노드처럼 구현됩니다.
예시) 헤더에서 함수 선언 후 cpp에서 OnItemPickedUp을 제외한 함수 구현
// 함수를 블루프린트에서 호출 가능하도록 설정
UFUNCTION(BlueprintCallable, Category="Item|Actions")
void ResetActorPosition();
// 블루프린트에서 값만 반환하도록 설정
UFUNCTION(BlueprintPure, Category = "Item|Properties")
float GetRotationSpeed() const;
// C++에서 호출되지만 구현은 블루프린트에서 수행
UFUNCTION(BlueprintImplementableEvent, Category = "Item|Event")
void OnItemPickedUp();
OnItemPickedUp은 C++ 구현하지 않고 BeginPlay 함수에 호출해놨음.
void AItem::ResetActorPosition()
{
SetActorLocation(FVector::ZeroVector);
}
float AItem::GetRotationSpeed() const
{
return GetRotationSpeed();
}
void AItem::BeginPlay()
{
Super::BeginPlay();
OnItemPickedUp();
}
빌드를 하고 에디터를 실행한 후 BP_Item의 이벤트 그래프에서 C++에서 작성한 함수를 검색하면 나온다.
BlueprintCallable은 실행핀이 있고
BlueprintPure는 Getter 노드로 생성되고
BlueprintImplementableEvent는 이벤트 노드로 생성되어 이벤트 그래프에서 구현을 할 수 있다.
C++에서 BeginPlay에 OnItemPickedUp을 호출해놔서 ResetActorPosition을 연결하고 실행을 하면 ResetActorPosition이 실행된다.
'언리얼 + cpp' 카테고리의 다른 글
언리얼C++ 2일차(트랜스폼) (0) | 2025.09.15 |
---|---|
언리얼C++ 2일차(UE_LOG, 라이프 사이클 함수) (0) | 2025.09.15 |
언리얼C++ 2일차(C++ 파일 삭제, C++로 컴포넌트 추가하기) (0) | 2025.09.15 |
언리얼 엔진 C++ 공부 1일차(폴더, 빌드, 라이브코딩, 빌드 문제 복구하기) (0) | 2025.09.12 |
UE_LOG를 활용한 로또 번호 생성기 구현하기 (1) | 2025.08.28 |