C++와 Unreal Engine으로 3D 게임 개발

C++와 Unreal Engine으로 3D 게임 개발 1-4

jh009 2026. 6. 7. 20:49

1-4. Actor 클래스에 컴포넌트 추가하기

1. Actor 클래스 코드 구조 이해하기

 

.h 파일 상단 코드

// 동일 헤더가 프로젝트 곳곳에서 여러 번 포함되더라도 컴파일러가 한 번만 처리
#pragma once 

// 언리얼에서 가장 기본이 되는 헤더
// 엔진 전역 타입, 매크로, 함수 등을 가져옴
#include "CoreMinimal.h"

// AActor 클래스 선언을 사용 가능하게 해줌
#include "GameFramework/Actor.h"

// 언리얼 헤더툴 (UHT)이 자동 생성하는 코드를 포함하는 것
// 항상 헤더의 마지막 줄에 위치 (다른 곳으로 이동하면 컴파일 오류)
#include "Item.generated.h"

.h 파일 클래스 선언부 코드

 

AItem

언리얼 엔진 C++에서는 클래스 이름에 접두사를 붙이는 접두사 규칙

  • A (Actor 계열), U (Object 계열), F (구조체), T (템플릿), E (열거형) 등
// 플렉션 시스템에 등록하는 매크로
UCLASS()

// AActor를 상속받아 AItem 클래스를 정의한다는 의미
// SPARTAPROJECT_API: 모듈 (현재 모듈은 SpartaProject) 외부에서도 클래스를 사용할 수 있게 하기 위한 매크로
class SPARTAPROJECT_API AItem : public AActor
{
		// UCLASS()와 짝을 이루어, 언리얼 헤더툴 (UHT)이 자동 생성한 코드를 삽입해 주는 매크로
		GENERATED_BODY()
	
public:
		// 생성자
		AItem();

protected:
		// 액터가 월드에 스폰 (배치된) 직후 한 번만 호출
		virtual void BeginPlay() override;
		// 매 프레임마다 호출
		virtual void Tick(float DeltaTime) override;
};

.cpp 파일 클래스 구현부 코드

 

#include "Item.h"

  • 자동 생성 매크로가 올바르게 확장되려면 짝이 되는 헤더를 가장 먼저 include 해야 함
  • .cpp 파일에서는 가장 첫 줄에 짝이 되는 헤더 파일을 포함해야 함
  • 포함하지 않을 경우, 예기치 않은 링커 오류가 발생
// 항상 첫 줄에 적기. 자신과 짝이 되는 헤더를 가장 먼저 include해야 함.
#include "Item.h"

// 생성자 구현부
AItem::AItem()
{
	PrimaryActorTick.bCanEverTick = true;
}

// BeginPlay() 구현부
void AItem::BeginPlay()
{
	// 부모 클래스(AActor)의 BeginPlay()를 먼저 호출
	Super::BeginPlay();
}

// Tick() 구현부
void AItem::Tick(float DeltaTime)
{
	// 부모 클래스(AActor)의 Tick() 먼저 호출
	Super::Tick(DeltaTime);
}

2. Actor 클래스에 컴포넌트 멤버 변수 추가하고 초기화하기

컴포넌트 (Component)

  • 언리얼 엔진에서 Actor가 어떤 역할을 하거나 특정 속성을 갖도록 만들어주는 부품 같은 개념
  • 한 Actor 내부에 여러 종류의 컴포넌트를 계층적으로 조합해 복합 기능을 구현함
  • 하나의 Actor가 여러 종류의 컴포넌트를 조합하여 다양한 기능을 구현할 수 있음

예시) Static Mesh Component + Audio Component + Collision Component → 충돌 시 소리가 나는 아이템


루트 컴포넌트와 Scene Component

  • 모든 Actor는 루트 컴포넌트 (Root Component)를 가져야 함
  • 루트 컴포넌트는 액터의 트랜스폼 (위치, 회전, 크기)을 정의하는 최상위 컴포넌트
  • 모든 하위 컴포넌트가 이를 기준으로 트랜스폼이 계산

보통 Scene Component를 루트 컴포넌트로 설정하여 액터의 트랜스폼을 관리

그 아래에 다양한 컴포넌트를 계층적으로 붙임

 

Scene Component

  • 모든 트랜스폼 속성만 가지는 비시각적인 컴포넌트
  • 직접적인 시각적 출력을 가지지 않지만, 다른 하위 컴포넌트들을 관리하는 기준점 역할

Static Mesh Component

  • 애니메이션이나 스켈레탈 본 없이 (움직임이 없고 단순 이동·회전만 하는) 정적 (Static) 3D 모델을 그리는 컴포넌트
  • 움직임이 단순하거나 없는 오브젝트에 주로 적합 (환경 오브젝트 (건물, 바위), 아이템, 단순 기믹 오브젝트 등)
  • 3D 모델을 표현하고, 물리 충돌과 관련된 기능도 제공

Static Mesh Component와 Scene Component 연결하기

 

Item.h 파일에서 다음과 같이 포인터 멤버 변수를 추가

 

Item.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"

UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
		GENERATED_BODY()
	
public:	
		AItem();

protected:
		// 루트 컴포넌트를 나타내는 Scene Component 포인터
		USceneComponent* SceneRoot;
		// Static Mesh Component 포인터
		UStaticMeshComponent* StaticMeshComp;
};

 

Item.cpp 

#include "Item.h"

AItem::AItem()
{
		// Scene Component를 생성하고 루트로 설정
		SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
		SetRootComponent(SceneRoot);

		// Static Mesh Component를 생성하고 Scene Component에 Attach
		StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
		StaticMeshComp->SetupAttachment(SceneRoot);
}

 

  • 필요한 함수 (BeginPlay, Tick)가 없거나 미사용 상태라면, 헤더와 .cpp 파일에서 제거해도 무방함
  • 필요할 때 다시 추가하면 됨

USceneComponent* SceneRoot

  • SceneRoot는 눈에 보이지 않는 논리적 컴포넌트로, 실제 3D 모델이나 시각적 요소를 가지지 않음

UStaticMeshComponent* StaticMeshComp

  • StaticMeshComp는 Static Mesh (정적 메시)를 렌더링하는 역할

CreateDefaultSubobject<T>(TEXT(""))

  • Unreal Engine에서 컴포넌트를 생성하고 초기화할 때 사용하는 함수
  • 템플릿 타입 <T>로 생성할 컴포넌트의 유형을 지정
  • "StaticMesh", "SceneRoot"는 각 컴포넌트의 식별 이름
  • TEXT() 매크로는 문자열을 유니코드로 처리하기 위한 것 → 언리얼 엔진 코드 표준에서 권장

SetRootComponent(SceneRoot)

  • 루트 컴포넌트를 SceneRoot로 설정
  • 루트 컴포넌트는 액터의 기본 위치, 회전, 크기를 정의
  • 다른 모든 하위 컴포넌트가 이를 기준으로 동작

SetupAttachment(SceneRoot)

  • StaticMeshComp를 SceneRoot에 부착 (Attach)
  • StaticMeshComp는 SceneRoot의 하위 컴포넌트로 동작
  • SceneRoot의 트랜스폼 변화에 따라 움직임

언리얼 에디터에서 컴포넌트 확인 

  • 언리얼 에디터 Content Browser → C++ Classes → SpartaProject → Public 폴더 안에 Item 클래스를 레벨 뷰포트에 다시 배치
  • 현재 월드 상에서는 Item이 보이지는 않음 / Outliner에서 Item 액터가 생성되어 있는 것을 확인 가능
  • Details 창 → Component 가 보임
  • 에디터 상에 Component들이 노출되도록 리플렉션 시스템에 등록하지 않았기 때문에 보이지 않는 것을 확인
  • RootComponent는 설정하지 않아도 기본적으로 리플렉션 시스템에 등록되어 Details 창에서 볼 수가 있음


3. 메시 및 머티리얼 할당하고 Actor 배치하기

Static Mesh Component의 주요 구성 요소

 

Static Mesh (스태틱 메시)

  • 3D 모델 (정적 메쉬 데이터)를 정의
  • 모델 파일이며, 언리얼 엔진에서는 .uasset 파일로 관리

Material (머티리얼)

  • 메쉬의 표면 시각적 속성을 정의
  • 색상, 질감, 반사율, 투명도 등의 속성을 설정
  • Static Mesh 에는 여러 개의 머티리얼 슬롯이 있을 수 있음
  • 슬롯은 메쉬의 특정 부분에 다른 머티리얼을 적용할 수 있도록 함

Static Mesh 및 Material 설정

 

Item.cpp

#include "Item.h"

AItem::AItem()
{
		// Scene Component를 생성하고 루트로 설정
		SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
		SetRootComponent(SceneRoot);

		// Static Mesh Component를 생성하고 Scene Component에 Attach
		StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
		StaticMeshComp->SetupAttachment(SceneRoot);
		
		// Static Mesh를 코드에서 설정
		static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Resources/Props/SM_Chair.SM_Chair"));
		if (MeshAsset.Succeeded())
		{
			StaticMeshComp->SetStaticMesh(MeshAsset.Object);
		}

		// Material을 코드에서 설정
		static ConstructorHelpers::FObjectFinder<UMaterial> MaterialAsset(TEXT("/Game/Resources/Materials/M_Metal_Gold.M_Metal_Gold"));
		if (MaterialAsset.Succeeded())
		{
			StaticMeshComp->SetMaterial(0, MaterialAsset.Object);
		}
}

 

ConstructorHelpers::FObjectFinder<T>

  • Unreal Engine에서 특정 리소스를 경로 기반으로 로드하는 클래스

TEXT("/Game/Resources/Props/SM_Chair.SM_Chair")

  • 리소스의 경로를 나타냄 
  • 리소스의 경로를 가져오려면 아래와 같이 해당하는 에셋을 우클릭 → Copy Reference 후 복붙
  • /Game 부터만 입력하면 되고, 앞에 경로는 삭제
  • /Game은 Unreal Engine에서 프로젝트의 Content 폴더를 나타냄

 

.Succeeded()

  • 지정된 경로에서 리소스를 성공적으로 찾았는지 확인
  • 경로가 잘못되었거나 리소스 파일이 누락된 경우 → 실패 / 이후 설정 함수가 호출되지 않음

SetStaticMesh(),  SetMaterial()

  • 성공적으로 로드된 Static Mesh를 StaticMeshComp에 설정
  • 로드된 Material을 StaticMeshComp의 특정 머티리얼 슬롯에 적용
  • 여기서는 첫 번째 머티리얼 슬롯 (Index 0)에 Material이 설정

언리얼 에디터에서 Actor 배치 및 테스트

  • 다시Item 클래스를 레벨 뷰포트에 배치
  • 현재 Details 창에서는 Component가 보이지 않고 에디터 상에서 할당은 불가능
  • 뷰포트 상에서 메시랑 머티리얼이 잘 할당되었다는 것을 확인 가능