PART 1 · 강의 2/7

리플렉션 시스템 기초

UCLASS, UPROPERTY, UFUNCTION으로 런타임 타입 정보 활용하기

01

리플렉션 시스템 개요

런타임에 타입 정보에 접근하는 메커니즘

리플렉션(Reflection)은 프로그램이 실행 중에 자신의 구조(클래스, 프로퍼티, 함수 등)를 검사하고 수정할 수 있는 기능입니다. 언리얼 엔진은 UHT(Unreal Header Tool)를 통해 이를 구현합니다.

타입 계층 구조 // 리플렉션 타입 계층 UField └─ UStruct ├─ UClass // 클래스 메타데이터 ├─ UScriptStruct // 구조체 메타데이터 └─ UFunction // 함수 메타데이터 └─ UEnum // 열거형 메타데이터 └─ FProperty // 프로퍼티 메타데이터
📌 UHT(Unreal Header Tool)의 역할

컴파일 전에 헤더 파일을 파싱하여 .generated.h 파일을 생성합니다. 이 파일에 리플렉션에 필요한 메타데이터가 포함됩니다.

02

UCLASS 지정자

클래스 레벨 메타데이터 설정

C++ UCLASS( Blueprintable, // BP에서 상속 가능 BlueprintType, // BP 변수 타입으로 사용 가능 Abstract, // 직접 인스턴스화 불가 NotBlueprintable, // BP 상속 금지 Transient, // 저장하지 않음 Config=Game, // Config 파일에서 설정 로드 DefaultToInstanced, // 인스턴스 기본값 EditInlineNew, // 프로퍼티 에디터에서 인라인 생성 meta=(DisplayName="My Class") ) class MYGAME_API UMyClass : public UObject { GENERATED_BODY() public: // StaticClass()로 UClass 접근 // UMyClass::StaticClass() };

클래스 정보 접근

C++ // 클래스 정보 얻기 UClass* MyClassInfo = UMyClass::StaticClass(); UClass* InstanceClass = MyObject->GetClass(); // 클래스 이름 FString ClassName = MyClassInfo->GetName(); // 부모 클래스 확인 if (MyObject->IsA<ACharacter>()) { // ACharacter 또는 그 자식 클래스 } // 동적 캐스팅 ACharacter* Character = Cast<ACharacter>(MyActor); if (Character) { // 캐스팅 성공 }
지정자 설명
Blueprintable 블루프린트에서 이 클래스를 상속할 수 있음
BlueprintType 블루프린트에서 변수 타입으로 사용 가능
Abstract 직접 인스턴스화 불가 (추상 클래스)
Transient 디스크에 저장되지 않음
Config=ConfigName 지정된 Config 파일에서 설정 로드
EditInlineNew 프로퍼티 창에서 인라인으로 생성 가능
03

UPROPERTY 지정자

프로퍼티 직렬화, 에디터 노출, 네트워크 복제

에디터 노출

C++ UCLASS() class UMyClass : public UObject { GENERATED_BODY() public: // 모든 곳에서 편집 가능 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats") float Health = 100.f; // 기본값만 편집 (클래스 기본 오브젝트에서만) UPROPERTY(EditDefaultsOnly) int32 MaxHealth = 100; // 인스턴스만 편집 (레벨에 배치된 액터) UPROPERTY(EditInstanceOnly) FString InstanceName; // 읽기 전용 표시 (수정 불가) UPROPERTY(VisibleAnywhere) int32 CurrentLevel; };

Blueprint 접근 및 네트워크

C++ // Blueprint 접근 제어 UPROPERTY(BlueprintReadOnly) float ReadOnlyValue; UPROPERTY(BlueprintReadWrite) float ReadWriteValue; // 네트워크 복제 UPROPERTY(Replicated) int32 ReplicatedValue; UPROPERTY(ReplicatedUsing=OnRep_Health) float NetworkedHealth; UFUNCTION() void OnRep_Health(); // 고급 지정자 UPROPERTY(Transient) // 저장하지 않음 float TemporaryValue; UPROPERTY(SaveGame) // 세이브 게임에 포함 int32 SavedProgress; UPROPERTY(meta=(ClampMin="0", ClampMax="100")) int32 ClampedValue;

Edit 계열

  • EditAnywhere - 어디서든 편집
  • EditDefaultsOnly - 기본값만
  • EditInstanceOnly - 인스턴스만

Visible 계열

  • VisibleAnywhere - 어디서든 보기
  • VisibleDefaultsOnly - 기본값만
  • VisibleInstanceOnly - 인스턴스만
04

UFUNCTION 지정자

함수의 Blueprint 노출, 네트워크, 이벤트 처리

C++ UCLASS() class UMyClass : public UObject { GENERATED_BODY() public: // Blueprint에서 호출 가능 UFUNCTION(BlueprintCallable, Category="MyFunctions") void CallableFunction(); // Pure 함수 - 상태 변경 없음, getter용 UFUNCTION(BlueprintPure, Category="MyFunctions") float GetHealth() const; // Blueprint에서 구현 (C++ 구현 없음) UFUNCTION(BlueprintImplementableEvent) void OnDamaged(); // C++ 기본 구현 + BP 오버라이드 가능 UFUNCTION(BlueprintNativeEvent) void OnHealed(); void OnHealed_Implementation(); // 기본 구현 };

네트워크 UFUNCTION

C++ // 서버에서 실행 (클라이언트 -> 서버 RPC) UFUNCTION(Server, Reliable) void ServerDoAction(); // 클라이언트에서 실행 (서버 -> 특정 클라이언트) UFUNCTION(Client, Reliable) void ClientReceiveData(); // 모든 클라이언트에서 실행 (서버 -> 모든 클라이언트) UFUNCTION(NetMulticast, Unreliable) void MulticastEffect(); // 콘솔 명령으로 실행 UFUNCTION(Exec) void CheatGodMode(); // 에디터에서 버튼으로 호출 UFUNCTION(CallInEditor) void TestFunction();
⚠️ BlueprintCallable vs BlueprintPure

BlueprintCallable은 실행 핀이 있고 상태를 변경할 수 있습니다. BlueprintPure는 실행 핀이 없고 값만 반환하며, 매 프레임 호출될 수 있으니 주의하세요!

05

USTRUCT와 UENUM

구조체와 열거형의 리플렉션

구조체 USTRUCT(BlueprintType) struct FCharacterStats { GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite) float Health = 100.0f; UPROPERTY(EditAnywhere, BlueprintReadWrite) float Mana = 50.0f; UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 Level = 1; UPROPERTY(EditAnywhere, BlueprintReadWrite) FString Name; };
열거형 UENUM(BlueprintType) enum class ECharacterState : uint8 { Idle UMETA(DisplayName="대기"), Walking UMETA(DisplayName="걷기"), Running UMETA(DisplayName="달리기"), Attacking UMETA(DisplayName="공격"), Dead UMETA(DisplayName="사망"), MAX UMETA(Hidden) }; // 사용 예시 UPROPERTY(EditAnywhere, BlueprintReadWrite) ECharacterState CurrentState = ECharacterState::Idle;
💡 UMETA 활용

DisplayName으로 에디터에 표시되는 이름을 지정하고, Hidden으로 에디터에서 숨길 수 있습니다.

SUMMARY

핵심 요약

  • 리플렉션 — UHT가 .generated.h 파일을 생성하여 런타임 타입 정보 제공
  • UCLASS — Blueprintable, Abstract, Config 등으로 클래스 동작 정의
  • UPROPERTY — EditAnywhere, BlueprintReadWrite, Replicated 등으로 프로퍼티 노출
  • UFUNCTION — BlueprintCallable, Server/Client, BlueprintNativeEvent 등
  • USTRUCT/UENUM — BlueprintType으로 블루프린트에서 사용 가능
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: RPG 캐릭터 스탯 구조체 구현

USTRUCT(BlueprintType)로 FCharacterStats 구조체를 만들고, UPROPERTY(EditAnywhere, BlueprintReadWrite)로 Strength, Dexterity, Intelligence, Vitality를 선언하세요. UENUM으로 ECharacterClass(Warrior, Mage, Archer)를 정의하세요.

실습 2: UFUNCTION 지정자 활용

RPG 캐릭터 클래스에 BlueprintCallable로 TakeDamage(), BlueprintPure로 GetCurrentHealth(), BlueprintNativeEvent로 OnLevelUp()을 구현하세요. CallInEditor로 테스트 함수도 추가하세요.

심화 과제: 리플렉션을 활용한 동적 프로퍼티 시스템

UClass::StaticClass()와 FProperty 이터레이터를 사용하여, 런타임에 캐릭터의 모든 UPROPERTY를 순회하며 값을 읽고 출력하는 디버그 유틸리티를 구현하세요. Cast<>와 IsA<>를 활용하여 타입 안전한 캐스팅을 연습하세요.