[C++ 기초 4편] C++ 클래스 구조와 UPROPERTY 시스템 정리

김여울·2025년 5월 15일

사전캠프

목록 보기
23/24

📄 헤더 파일 (Class1Character.h)

  • 클래스 선언부
  • 리플렉션을 위해 반드시 포함해야 하는 매크로들 존재
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Class1Character.generated.h"

1️⃣ 리플렉션(Reflection)

  • 프로그램이 자기 자신을 탐색하고 정보에 접근할 수 있는 기능
  • 언리얼에서는 리플렉션을 통해 에디터에서 변수에 접근하거나, 블루프린트에서 함수를 사용할 수 있게 만듦
    • GENERATED_BODY() : 언리얼 매크로 시스템에서 필수로 넣어야 하는 매크로
    • generated.h 파일 : 리플렉션 처리를 위한 자동 생성 파일

2️⃣ Unreal Property System

  • 언리얼에서는 특정 변수나 함수, 클래스에 매크로를 붙여야 에디터나 블루프린트에서 인식할 수 있음

✅ 클래스 : UCLASS

UCLASS()
class AClass1Character : public ACharacter
  • A로 시작하는 이유: 언리얼에서는 AActor를 상속받은 클래스는 모두 A로 시작

✅ 변수 : UPROPERTY

UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera, meta=(AllowPrivateAccess="true"))
USkeletalMeshComponent* Mesh1P;
  • UPROPERTY를 붙이면 언리얼의 가비지 컬렉터가 해당 변수를 관리함
  • VisibleAnywhere : 어디서든 편집 가능
  • BlueprintReadOnly : 블루프린트에서는 읽기만 가능
  • AllowPrivateAccess : private 변수라도 에디터에서 노출

✅ 함수: UFUNCTION

UFUNCTION(BlueprintCallable, Category="MyFunctions")
void DoSomething();
  • UFUNCTION은 해당 함수를 언리얼 시스템(특히 블루프린트)에 노출시킴
  • BlueprintCallable : 블루프린트에서 직접 호출할 수 있음
  • BlueprintImplementableEvent : C++에서는 선언만 하고, 실제 로직은 블루프린트에서 구현 가능
  • Server, Client, NetMulticast : 네트워크 함수 지정

❓ 언제 UPROPERTY가 필요할까

상황UPROPERTY 필요 여부이유
클래스 내부에서만 사용❌ 필요 없음C++ 코드 안에서만 쓰면 일반 변수로 충분
에디터에서 값을 수정하고 싶음✅ 필요디자이너가 수정할 수 있도록 하기 위해
블루프린트에서 읽거나 쓰고 싶음✅ 필요리플렉션을 통해 노출되어야 함
언리얼의 가비지 컬렉터(GC)가 관리해야 함✅ 필요UPROPERTY를 통해 메모리 관리 대상 등록됨

❓ UPROPERTY를 쓰는 이유

  1. 에디터와 블루프린트 노출
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera, meta=(AllowPrivateAccess="true"))
USkeletalMeshComponent* Mesh1P;
  • VisibleAnywhere 에디터의 모든 섹션에서 해당 값을 보기만 가능 (수정 불가)
  • BlueprintReadOnly 블루프린트에서 읽을 수는 있으나 값 대입은 불가능
  • meta = (AllowPrivateAccess="true") : private으로 선언된 변수라도 에디터에 노출 가능
    ➡ 변수의 가시성과 접근 제어를 UPROPERTY의 옵션으로 상세하게 지정할 수 있음
  1. Garbage Collector(가비지 컬렉터)와의 연동
  • 가비지 컬렉터란?
    • C++에는 기본적으로 자동 메모리 정리 기능이 없지만,
      언리얼은 자체적으로 사용하지 않는 객체를 정리해주는 시스템을 갖추고 있음
    • 언리얼에서 관리되는 UObject 기반 객체들 (컴포넌트, 액터 등)은 가비지 컬렉터가 추적해야 함
    • 가비지 컬렉터가 객체를 추적하려면 해당 포인터가 UPROPERTY를 통해 노출되어 있어야 함

⚠️ 기본형(int 등) 변수와 UPROPERTY 사용 여부

  • 기본 타입(int, float 등)은 무조건 UPROPERTY를 붙일 필요는 없다
  • 하지만 에디터나 블루프린트에서 보여주거나 수정해야 할 경우에만 UPROPERTY로 명시해야 한다

🧩 예시
❌ 일반 변수 (C++ 내부에서만 사용)

int KillCount;

⭕ 에디터에서 보여주고 싶은 변수

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
int KillCount;
  • EditAnywhere : 에디터에서 수정 가능
  • BlueprintReadWrite : 블루프린트에서 읽고 쓸 수 있음

3️⃣ 언리얼 클래스 접두어 규칙

접두어의미예시
AAActor 기반 클래스 (게임 내 존재하는 객체)AClass1Character, AMyEnemy
UUObject 기반 클래스 (컴포넌트, 데이터 등)USkeletalMeshComponent, UAnimInstance
F구조체 (struct)FVector, FRotator
E열거형 (enum)EWeaponType, EMovementState
I인터페이스 (interface)IInteractable, IDamageable

🧩 예시

USkeletalMeshComponent* Mesh1P;
  • U UObject 기반 클래스
  • SkeletalMeshComponent 메시(모델)와 애니메이션을 처리하는 컴포넌트
  • * 포인터 (참조를 위한 것)
  • Mesh1P 보통 1인칭 캐릭터의 몸체에 붙이는 메시

4️⃣ 포인터(*) 사용 이유

  • 언리얼에서는 대부분의 컴포넌트나 오브젝트가 new 키워드 없이 동적 생성되어 관리됨
  • 이들은 힙(heap)에 올라가 있고, 우리는 주소값만 참조해서 사용
  • 장점
    • 데이터를 복사하지 않아 메모리 효율적
    • 참조를 끊거나 연결해서 객체 생명주기 관리 가능
    • 언리얼 가비지 컬렉터(GC)와도 잘 작동



✨ 소스 파일 (Class1Character.cpp)

1️⃣ 문자열 처리 타입

타입설명
FName한 번 생성 후 수정 불가. 성능 최적화됨
FTextUI용 텍스트, 로컬라이징 가능
FString일반 문자열
  • FName(TEXT("MyComponent"))TEXT() 매크로와 함께 사용

2️⃣ 예시 함수 및 속성

Mesh1P->SetOnlyOwnerSee(true);        // 나만 보이게 설정
Mesh1P->bCastDynamicShadow = false;   // 그림자 비활성화

3️⃣ 입력 바인딩 : BindAction

InputComponent->BindAction("Jump", IE_Pressed, this, &AClass1Character::Jump);
  • "Jump"라는 입력이 들어오면 해당 함수를 실행하도록 연결

💡 메시 임포트 팁

  • Skeletal Mesh를 가져올 때 애니메이션 포함된 경우
    • 메시 임포트 옵션에서 애니메이션 체크 해제 ☐ 필요

0개의 댓글