1. 헤더파일
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
일단 이 3개를 가져와준다
CoreMinimal.h : 코어 미니멀 이란 이름에 맞게 언리얼 엔진의 기본 클래스를 포함한다. 필수적인 기본 기능들을 제공.
GameFramework/Actor.h : 이 클래스가 Actor기반의 클래스라는 걸 나타낸다.
Item.generated.h : Unreal Tool에서 만들어준것으로 언리얼 엔진의 매크로와 기능을 활용하기 위해 필요 그리고 무조건 무조건 #include의 맨 마지막에 있어야된다 안그러면 버그가난다.
UCLASS()
class SETTING_API AItem : public AActor
{
GENERATED_BODY()
UCLASS() : 이건 언리얼 엔진에서 이 클래스를 하나의 객체로 받아들일 수 있게해주는 녀석이다.
SETTING_API: 이 매크로는 DLL의 API를 정의하는 데 사용됩니다. 이 클래스가 다른 모듈에서 접근 가능하다는 것을 나타냅니다.
AItem : public AActor: AItem 클래스가 언리얼의 기본 액터 클래스인 AActor를 상속받고 있음을 나타냅니다. 따라서 AItem은 액터로서의 모든 기능을 가진다. 언리얼은 강제로 이름 앞에 타입을 넣게 만들어놨다.
GENERATED_BODY(): 언리얼의 매크로로, 클래스의 생성자 및 기타 필수적인 기능을 자동으로 생성.
public:
AItem();
protected:
USceneComponent* SceneRoot;
UStaticMeshComponent* StaticMeshComp;
AItem() : Item 클래스 생성자이다. 위에서 GENERATED_BODY():가 분명히 클래스의 생성자 및 필수적인 기능들을 자동으로 생성한다고 했는데 이게 왜 필요한지 궁금한사람이 있을 수 있다. 이게 헷갈렸었다.
GENERATED_BODY()의 역할
- 자동 코드 생성: GENERATED_BODY()는 Unreal Engine의 매크로로, 클래스의 기본적인 기능을 자동으로 생성합니다. 여기에는 다음과 같은 것들이 포함됩니다:
- 리플렉션 시스템을 위한 메타데이터.
- 가비지 컬렉션을 위한 기본 설정.
- 기본 생성자 및 복사 생성자와 같은 필수적인 메서드의 선언.
AItem() 생성자의 역할
- 사용자 정의 초기화: AItem() 생성자는 클래스 인스턴스가 생성될 때 호출되는 사용자 정의 생성자입니다. 이 생성자는 다음과 같은 작업을 수행하는 데 사용됩니다:
- 멤버 변수 초기화.
- 컴포넌트 추가 및 설정.
- 기타 초기화 로직(예: 이벤트 바인딩, 상태 설정 등).
이렇게 GENERATED_BODY()는 클래스의 기본적인 기능을 제공하는 반면, AItem() 생성자는 개발자가 원하는 초기화 로직을 추가하는 데 사용된다.
USceneComponent* SceneRoot : 씬의 루트 컴포넌트를 나타내는 포인터다. 이 컴포넌트는 액터의 위치, 회전 및 스케일을 관리. 이게 없으면 위치를 잡을 수 없다. 세계를 기준으로 액터에 위치 개념을 넣는다고 생각하면 된다.
UStaticMeshComponent* StaticMeshComp : 정적 메시를 렌더링하는 컴포넌트를 나타내는 포인터. 이 컴포넌트를 통해 3D 모델이 씬에 표시된다. Static인걸 보면 알겠지만 정적이라 변하지 않는 액션이 없는 액터를 만들거기 때문에 사용해줬다.
그래서 완성된 헤더파일은
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
UCLASS()
class SETTING_API AItem : public AActor
{
GENERATED_BODY()
public:
AItem();
protected:
USceneComponent* SceneRoot;
UStaticMeshComponent* StaticMeshComp;
};
2. CPP파일.
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick :언리얼에서 게임의 각 프레임마다 특정 작업을 수행하도록 설정할 수 있는 시스템
bCanEverTick = true : 불리언(bool) 타입의 속성 멤버를 true로 설정합니다.
대충 요약해서 보면 나오자 마자 프레임에 맞춰 업데이트를 해준다고 보면되는데 이러면 무거워질까봐 걱정이 됐었다.
하지만 언리얼엔진에서는 필요한 액터만 틱을 활성화해주는 기능이 있는데 그게 bCanEverTick이다.
SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
SetRootComponent(SceneRoot);
SceneComponent : 3D공간에서 위치와 회전을 갖고 있는 기본적인 구성 요소.
TEXT("SceneRoot") : 생성되는 서브 오브젝트의 이름 선언
SetRootComponent(SceneRoot) : 현재 액터의 루트 구성 요소를 설정하는 함수. 이 호출을 통해 생성된 SceneRoot를 액터의 루트로 설정하기 때문에 이후에 추가하는 다른 구성요소들은 이 루트에 종속된다. 이걸 기준으로 이동하거나 한다는 뜻
한마디로 SceneRoot라는 변수는 3D공간에서 위치와 회전등의 여러 기본 요소들이 들어가게 되고 SetRootComponent를 통해 이 액터에서 사용되는 모든게 이녀석에 종속되게된다.
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
StaticMeshComp->SetupAttachment(SceneRoot);
StaticMeshComp : UStaticMeshComponent* 타입의 포인터 변수 이름
Create Default Sub object : 위에서 설명했던거랑 같은 액터의 기본 구성 요소를 생성하는 함수다.
UStaticMeshComponent : 정적 메시를 표시하는 구성요소.
TEXT("StaticMesh") : 구성요소의 이름
SetupAttachment->SetupAttachment(SceneRoot) : 생성된 StaticMeshComp를 SceneRoot에 부착하는거다. 즉 액터가 회전을 하면 스태틱 매시도 같이 회전하고 이동하면 같이 이동하는거라고 보면 된다.
그러면 이제 내가 만든 액터에 매시를 넣어주면 된다.
일단 매시의 위치가 필요하다. 위치를 알아야 갖다 붙힐 수 있기 때문에

내가 원하는 매시에 우클릭을 하여 레퍼런스 복사를 해주자.

그리고 붙여넣으면 이렇게 보일텐데 붉은색 말고는 다 지워주면 된다.
그리고 코드를 만들면 이렇게되는데
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT(" / Game / Resources / Props / Pillar_50x500.Pillar_50x500"));
static ConstructorHelpers : 언리얼에서 자산을 로드하는데 사용되는 유틸리티 클래스를 제공하는 네임스페이스다.
FObjectFinder<UStaticMesh> : 오브젝트 찾기. StaticMesh타입 이라고 생각하면 된다.
MeshAsset(TEXT(" / Game / Resources / Props / Pillar_50x500.Pillar_50x500")) : 위치를 넣어준거다.
그냥 경로에서 에셋을 찾는 코드다.
if (MeshAsset.Succeeded())
{
StaticMeshComp->SetStaticMesh(MeshAsset.Object);
}
if (MeshAsset.Succeeded()) : 자산의 로드 성공여부 확인
StaticMeshComp->SetStaticMesh(MeshAsset.Object) : 스태틱 매시에 내가 불러온 자산 집어넣기
만약 파일의 위치가 바뀌거나 삭제된 경우 심각한 오류가 생길 수 있으니 불러오는데 성공하였다면 집어넣어라~ 라는 일종의 안전장치이다.
#include "Item.h"
AItem::AItem()
{
PrimaryActorTick.bCanEverTick = true;
SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
SetRootComponent(SceneRoot);
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
StaticMeshComp->SetupAttachment(SceneRoot);
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT(" / Game / Resources / Props / Pillar_50x500.Pillar_50x500"));
if (MeshAsset.Succeeded())
{
StaticMeshComp->SetStaticMesh(MeshAsset.Object);
}
static ConstructorHelpers::FObjectFinder<UMaterial>MaterialAsset(TEXT("/ Game / Resources / Materials / M_Armor.M_Armor"));
if (MaterialAsset.Succeeded())
{
StaticMeshComp->SetMaterial(0, MaterialAsset.Object);
}
}
이렇게 CPP파일이 나온다.
개념이 중요해서 하나하나 무슨일 하는지 한번 되짚어봤다.
'언리얼 공부 > C++' 카테고리의 다른 글
순수가상함수, 추상클래스 그리고 인스턴스 (0) | 2025.02.20 |
---|---|
플로우 차트 (0) | 2025.02.18 |
FPS무기 구조 생각 (0) | 2025.02.17 |
일정 주기로 나왔다 사라지는 발판 (0) | 2025.02.04 |
액터 회전, 반복 이동 (0) | 2025.02.03 |