언리얼 엔진을 학습하다 보면, 가장 먼저 접하게 되는 개념 중 하나가 UObject와 AActor이다. 둘 다 엔진에서 매우 중요한 클래스 계층을 이루고 있으므로, 차이점을 확실히 알아두면 좋다.
UObject)의 개념UObject는 언리얼 엔진에서 모든 클래스의 최상위 부모이다.AActor)의 개념AActor는 UObject를 확장(상속)한 클래스로, 월드에 배치(Spawn) 할 수 있다.AActor를 기반으로 제작한다.이제 Actor를 상속받은 새로운 C++ 클래스를 만들어, 월드에 배치해 보는 예시를 살펴보자.
Actor를 선택한 뒤 Next 버튼을 누른다.
Actor가 안 보인다면, “All Classes” 탭에서 직접 검색해보자.Item으로 하고, Class Type (폴더 위치)은 기본값인 Public으로 둔 뒤 “Create Class”를 누른다.

Source/SpartaProject → Public 폴더 아래에 Item.h, Private 폴더 아래에 Item.cpp 파일이 생성된 것을 확인할 수 있다.
.h가 Public 폴더에, .cpp가 Private 폴더에 생긴다.#include할 수 있어 편리하다..h와 .cpp 모두 Private 폴더에 저장된다.
Public 폴더 안에 Item 클래스를 레벨 뷰포트로 드래그 & 드롭하여 배치하자.


작업 중에 사용하지 않게 된 클래스는 삭제해야 할 때가 있다. 단순히 언리얼 에디터 Content Browser에서 Delete만 하는 것으로는 완전히 제거되지 않으니, 아래 절차를 따라야 안전하게 삭제할 수 있다.
.h와 .cpp 파일을 각각 우클릭 → Remove를 선택하자.
Source/SpartaProject 아래의 Public 혹은 Private 폴더로 이동하자..h, .cpp 파일을 직접 삭제하자.
언리얼 엔진에서 C++ 클래스를 새로 만들면, 일반적으로 헤더(.h) 파일과 구현(.cpp) 파일이 한 쌍으로 자동 생성된다. 여기서는 지난 강의에서 만들었던 Item 클래스를 예로 들어, 헤더 파일의 구조와 각 부분에서 어떤 역할을 하는지를 자세히 살펴보자.
1️⃣ .h 파일 상단 코드
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
#pragma once#ifndef ~ #define ~ #endif 방식을 사용했지만, 대부분의 최신 C++ 프로젝트에서 #pragma once를 권장한다.#include "CoreMinimal.h"FString, TArray 등)과 매크로(UE_LOG 등), 각종 유틸 함수들이 정의되어 있다.#include "GameFramework/Actor.h"AActor를 상속받기 위해 필요한 헤더 파일이다.#include "Item.generated.h"2️⃣ .h 파일 클래스 선언부 코드
UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
GENERATED_BODY()
public:
// 생성자
AItem();
protected:
// 액터가 월드에 '배치된 직후' 한 번만 호출
virtual void BeginPlay() override;
// 매 프레임마다 자동으로 호출
virtual void Tick(float DeltaTime) override;
};
UCLASS()class SPARTAPROJECT_API AItem : public AActorAActor를 상속받아 AItem 클래스를 정의한다는 의미이다.AItemA (Actor 계열), U (Object 계열), F (일반 구조체), T (템플릿), E (열거형) 등Actor 클래스를 상속받았으므로, AItem 으로 생성된다.SPARTAPROJECT_API 는 이 클래스를 모듈 (여기서는 SpartaProject) 외부로 Export하기 위한 매크로이다. DLL 등으로 빌드할 때 필요한 선언이다.GENERATED_BODY()UCLASS()와 짝을 이루어, 엔진 리플렉션에 필요한 코드를 자동 생성해 주는 매크로이다. (이후 강의에서 배우는 내용)AItem() - 생성자BeginPlay()Tick(float DeltaTime)3️⃣ .cpp 파일 클래스 구현부 전체 코드
#include "Item.h" // 자기 자신과 짝이 되는 헤더를 가장 먼저 include해야 함.
// 생성자 구현부
AItem::AItem()
{
PrimaryActorTick.bCanEverTick = true; // (이후 강의에서 배우는 내용)
}
// BeginPlay() 구현부
void AItem::BeginPlay()
{
// 부모 클래스(AActor)의 BeginPlay()를 먼저 호출
Super::BeginPlay();
}
// Tick() 구현부
void AItem::Tick(float DeltaTime)
{
// 부모 클래스(AActor)의 Tick() 먼저 호출
Super::Tick(DeltaTime);
}
#include "Item.h"AItem(), BeginPlay(), Tick(float DeltaTime)Item 클래스를 뷰포트에 배치하였음에도 불구하고, 월드 상에서 보이지 않았다. 그 이유는 3D 메시를 설정하지 않았기 때문에 보이지 않기 때문이다.
#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* SceneRootUStaticMeshComponent* StaticMeshCompCreateDefaultSubobject<T>(TEXT(""))<T>로 생성할 컴포넌트의 유형을 지정한다."StaticMesh", "SceneRoot"는 각 컴포넌트의 식별 이름이 된다.TEXT() 매크로는 문자열을 유니코드로 처리하기 위한 것으로, 언리얼 엔진 코드 표준에서 권장한다.SetRootComponent(SceneRoot)SetupAttachment(SceneRoot)StaticMeshComp를 SceneRoot에 부착 (Attach)한다.StaticMeshComp는 SceneRoot의 하위 컴포넌트로 동작하며, SceneRoot의 트랜스폼 변화에 따라 움직인다.
.uasset 파일로 관리된다.
이런식으로 내가원하는 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_Star_B.SM_Star_B"));
if (MeshAsset.Succeeded())
{
StaticMeshComp->SetStaticMesh(MeshAsset.Object);
}
// Material을 코드에서 설정
static ConstructorHelpers::FObjectFinder<UMaterial> MaterialAsset(TEXT("/Game/Resources/Materials/M_Coin_A.M_Coin_A"));
if (MaterialAsset.Succeeded())
{
StaticMeshComp->SetMaterial(0, MaterialAsset.Object);
}
}
ConstructorHelpers::FObjectFinder<T>
TEXT("/Game/Resources/Props/SM_Chair.SM_Chair"):
/Game 여기서부터만 입력하면 되고, 앞에 경로는 삭제를 해준다./Game은 Unreal Engine에서 프로젝트의 Content 폴더를 나타낸다..Succeeded()
SetStaticMesh(), SetMaterial()
StaticMeshComp에 설정한다.StaticMeshComp의 특정 머티리얼 슬롯에 적용한다. 여기서는 첫 번째 슬롯 (Index 0)에 Material이 설정된다.Item 클래스를 레벨 뷰포트에 배치해보자.
