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

김여울·2025년 6월 30일
0

내일배움캠프

목록 보기
33/114

📍 1주차 3강 ~ 4강

Class

언리얼 클래스 상속 구조

UObject               ← 모든 언리얼 클래스의 조상
 ├── UActorComponent  ← 컴포넌트 (기능 부여용, 붙일 수 있음)
 ├── AActor           ← 게임 월드에 존재하는 모든 액터의 기반
 │    ├── APawn       ← 조종 가능한 액터 (플레이어나 AI가 조종)
 │    │    └── ACharacter  ← 사람 형태의 폰 (걷기/점프 지원됨)
 │    └── AStaticMeshActor ← 정적인 3D 모델 오브젝트
 ├── UGameInstance    ← 게임 전반 상태 관리 (씬 바뀌어도 안 사라짐)
 ├── UUserWidget      ← UI 요소
 └── 등등...

Object

  • 언리얼 엔진 내 모든 클래스의 조상(뿌리)이 되는 클래스
  • 모든 클래스는 오브젝트 클래스를 상속 받음
  • 그러나 월드에 배치는 할 수 없음! (추상적 개념)
  • 플레이어의 스탯같이 시각적으로 보이지 않지만 어떤 데이터를 담는 구조 같은 건 오브젝트를 상속 받음

Actor

  • 월드에 직접 배치 가능
  • 좌표 정보 갖고 있음
  • 캐릭터, 몬스터, 아이템, 파티클 등 모두 액터를 상속 받음

접근 제한자 (Access Specifiers)

Public으로 생성

.h → public → 다른 모듈(폴더)에서도 얘 include(참조) 가능
.cpp → private

Private으로 생성

.h .cpp → private 안에 생성 → 다른 모듈에서 include 불가능


Class 삭제하기

1️⃣ .cpp .h 모두 Visual Studio에서 remove (가상 구조에서 삭제) → Save All
2️⃣ .cpp .h 모두 로컬 프로젝트 Source 폴더에서 삭제 (물리적 삭제)
3️⃣ Unreal Editor 종료 후 VS 2022에서 빌드
4️⃣ 빌드 완료 후 F5 → 에디터 실행

헤더파일 | 소스파일

헤더파일 (Item.h)

#pragma once	// 중복 컴파일을 방지

#include "CoreMinimal.h"	// 로그함수, UE 제공 기본 타입 함수
#include "GameFramework/Actor.h"	// Actor Class에 관한 정보
#include "Item.generated.h"	// 리플렉션 시스템

// 클래스 선언
// 이 클래스를 리플렉션 시스템에 등록하겠다
UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
	GENERATED_BODY()	// 매크로(리플렉션 시스템)
	
public:	
	AItem();	// 생성자

protected:	// 부모 상속할 때만 접근 가능
	virtual void BeginPlay() override;
	virtual void Tick(float DeltaTime) override;

};
  • #pragma once

    • 헤더 파일 중복 컴파일을 방지하는 매크로
  • #include "CoreMinimal.h"

    • 로그함수, UE 제공 기본 타입 함수들을 포함하는 헤더파일
    • 헤더파일 상단에 위치하는 게 좋음
  • #include "GameFramework/Actor.h"

    • Actor Class에 관한 정보를 가진 헤더파일
    • Item은 Actor를 상속받음 → Actor Class 헤더파일 포함해야 함
  • #include "Item.generated.h"

    • 리플렉션 시스템 관련 헤더파일
    • 리플렉션 시스템 : 짠 코드들을 블루프린트에서 볼 수 있게 해줌
      • "Item.generated.h", UCLASS(), GENERATED_BODY()
  • SPARTAPROJECT_API

    • 모듈 밖으로도 내보낼 수 있는 매크로
    • 빌드할 때 중요한 매크로
  • BeginPlay, Tick

    • 액터의 라이프사이클 함수

소스파일 (Item.cpp)

헤더파일에서 선언한 함수들 구현

#include "Item.h"

AItem::AItem()	// 생성자 구현
{
 	// Tick 함수 관련된 선언 (나중에 배움)
	PrimaryActorTick.bCanEverTick = true;

}

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

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

}

기본 클래스 접두어

접두어설명
AActor 클래스 (예: ACharacter, APlayerController)
UUObject 기반 클래스 (예: UUserWidget, UMaterial)
F구조체 (Struct) (예: FVector, FHitResult)
E열거형 (Enum) (예: EGameState, EWeaponType)
T템플릿 클래스 (예: TArray, TMap)
I인터페이스 (Interface) (예: IInteractable)

C++로 Actor, Component, Material 만들기

Actor

Actor Class 만들고 월드에 배치하면
1️⃣ 메시 없음 → 아무 것도 없음 (투명)
2️⃣ Root Component 없음 → (0, 0, 0) 에 배치
➡ Actor는 최소한 하나 이상의 컴포넌트 (Root Component)있어야 제대로 Actor의 기능을 가짐

Component

기능이 있는 하나의 부품

Scene

  • 여러 개의 Component를 붙일 때 Root Component로 함
    • 하나의 Component만 할 거면 그걸 root로 해도 됨
    • (예) Audio 기능만 → Root Component = Audio
  • 트랜스폼(좌표 정보) 가지고 있음

StaticMesh

  • Static 고정된 Mesh 모델 (건물, 배경 등)
    • 캐릭터 같은 움직이는 메쉬는 Skeletal Mesh
  • Static Mesh Model = 모양
  • Materials Texture = 색상, 질감 등

C++ → Actor, Component

C++로 만들면 Root Component는 자동으로 리플렉션 되는데 StaticMesh는 안된다
→ 코드로 스태틱 메시 설정해줘야 함

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:	
	// Sets default values for this actor's properties
	AItem();

protected:
	// 포인터 형태로 멤버 변수 선언 (텅빈 포인터 -> 생성자에서 할당)
	UPROPERTY()
	USceneComponent* SceneRoot;	// Root Component로 SceneComponent 생성 

	UPROPERTY()
	UStaticMeshComponent* StaticMeshComp;
};

Item.cpp

#include "Item.h"

AItem::AItem()
{
	// 포인터일 뿐이니까 SceneComponent를 생성해 연결해야 함
	// <> 에 뭘 생성할 지 쓰면 됨
	// () 함수인자는 컴포넌트의 이름
	SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));

	// RootComponent로 만들어주기
	SetRootComponent(SceneRoot);

	// StaticMesh ptr에도 연결
	StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));

	// StaticMesh는 RootComponent의 자손이니까 자손으로 붙여주기
	StaticMeshComp->SetupAttachment(SceneRoot);
}

C++ → StaticMesh, Material

Copy Reference

콘텐츠 브로어에서 스태틱 메시, 머티리얼 우클릭 후 Copy Reference(위치 경로 가져옴)

'/Game/Resources/Props/SM_Chair.SM_Chair'
'/Game/Resources/Materials/M_Potion_MP.M_Potion_MP'

Static Mesh, Material 코드

Item.cpp

#include "Item.h"

AItem::AItem()
{
	SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
	SetRootComponent(SceneRoot);

	
	StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
	StaticMeshComp->SetupAttachment(SceneRoot);

// 💡 여기부터!!
// Mesh나 Resource를 load하는 클래스
// FObjectFinder가 “로드”를 수행하는 클래스
// Static 타입의 변수 선언
	static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Resources/Props/SM_Chair.SM_Chair"));
	if (MeshAsset.Succeeded())	// MeshAsset이 성공적으로 가져와졌는지
	{	// 확인하고 싶은 if문 안에
		StaticMeshComp->SetStaticMesh(MeshAsset.Object);	//MeshAsset의 Object를 갖고와서 할당해줌
	}

	// Material 할당
	static ConstructorHelpers::FObjectFinder<UMaterial> MaterialAsset(TEXT("/Game/Resources/Materials/M_Potion_MP.M_Potion_MP"));
	if (MaterialAsset.Succeeded())
	{
		StaticMeshComp->SetMaterial(0, MaterialAsset.Object);	// Index 0 : 첫 번째 Material 이걸로 설정하겠다
	}
}
  • ConstructorHelpers

    • ConstructorHelpers::FObjectFinder 같은 방식으로 사용함
    • 생성자 내부에서만 사용 가능
    • 주로 /Game/경로로 리소스 로드할 때 쓰임
      항목설명
      🔒 생성자에서만 사용 가능BeginPlay, Tick에서는 못 씀
      📁 경로는 정확해야 함에셋 경로 틀리면 무조건 실패
      Succeeded() 꼭 체크없으면 크래시 날 수도 있음
  • FObjectFinder

    • “로드”를 수행하는 클래스
      → LoadObject(), LoadClass()도 같은 개념
  • 로드(load)

    • 파일이나 리소스를 메모리로 불러오는 것
    • 디스크에 있는 에셋(Mesh, Texture, Sound 등)을 실행 중 메모리에 올리는 행위

💭

다시 언리얼로 돌아오니까 훨씬 재밌다.
C++ 처음 배웠을 때도 재밌다고 느꼈던 것 같은데.. ㅎ
튜터님께서 하나부터 열까지 알려주셔서 어느 부분을 잊었는지 다시 알 수 있었고 나름 두 달동안 공부하면서 꽤 많은 걸 배웠구나 느꼈다.
그동안은 액터를 마우스로만 만든 것 같은데 비주얼 스튜디오를 연동해서 하니까 뭔가 멋있는데 결국은 또 C++이라 얼른 익숙해져야 할 것 같다.

0개의 댓글