[UE5] AActor 및 C++ 클래스 생성
AActor
AActor는 UObject 계열을 기반으로 하는 클래스이며, 월드에 배치될 수 있는 모든 액터의 베이스 클래스입니다.
StaticMeshActor, CameraActor, PlayerStartActor가 액터입니다.
월드로부터 틱과 시간 서비스를 제공받습니다.
게임 플레이 코드(C++/BP)를 통해 월드에 생성 및 배치(Spawn) 할 수 있고, 소멸 또한 가능합니다.
액터는 논리적인 개념으로, 실질적인 구현과 기능은 컴포넌트가 진행하고 액터는 다수의 컴포넌트(메시, 파티클, 사운드)를 소유합니다.
여기서 다수의 컴포넌트 중 계층 구조의 최상위에 위치한 컴포넌트를 루트 컴포넌트(Root Component)라고 합니다.
액터는 일반적으로 루트 컴포넌트를 가집니다.
액터는 트랜스폼 데이터를 직접 저장하지 않고, 루트 컴포넌트의 트랜스폼 데이터를 사용합니다.
즉, 루트 컴포넌트의 트랜스폼이 액터의 트랜스폼을 결정합니다.
데이터 처리나 매니저 역할 등 시각적이나 물리적인 형태가 전혀 필요하지 않으며 논리적 기능만 수행하는 경우 루트 컴포넌트를 가지지 않도록 하기도 합니다.
실제 게임 세계에서 보이고 상호작용하는 캐릭터, 적 몬스터, 무기, 조명, 파티클 효과 등은 주로 AActor를 기반으로 제작합니다.
AActor 생성
AActor를 상속 받는 새로운 C++ 클래스를 만들어 보겠습니다.
언리얼 에디터 상단 메뉴에서 “툴” > “새로운 C++ 클래스”를 선택합니다.
팝업 창이 뜨는데, 일반 클래스 탭에서 Actor를 선택한 뒤 다음 버튼을 누릅니다.
혹은 모든 클래스 탭에서 Actor를 검색하는 등 찾은 뒤 다음 버튼을 누릅니다.
그럼 창이 변경되며, 클래스 타입, 이름, 경로 등을 지정할 수 있습니다.
해당 부분을 원하는 대로 변경하며, 클래스 생성을 클릭하면 생성됩니다.
클래스 타입의 경우 다음과 같습니다.
Public으로 생성할 경우 .h가 Public 폴더에, .cpp가 Private 폴더에 생깁니다.
프로젝트의 다른 모듈에서 쉽게 #include할 수 있습니다.
Private로 생성할 경우 .h와 .cpp가 모두 Private 폴더에 저장됩니다.
해당 모듈에서만 접근 가능하게 되며 특정 로직이나 구현을 캡슐화해서 외부에 노출하고 싶지 않을 때 사용합니다.
잠시 후 자동 빌드가 진행되며, 완료 되면 비주얼 스튜디오에서 프로젝트가 변경되었다는 메시지가 뜰 수 있습니다.
여기서 Reload All을 선택합니다.
비주얼 스튜디오의 솔루션 탐색기를 살펴보면 다음과 같이 파일이 생성된 것을 확인 할 수 있습니다.
저의 경우 클래스 타입을 Public으로 설정했기 때문에 다음과 같은 구조가 됐습니다.
언리얼 에디터의 콘텐츠 브라우저에도 변화가 있는데, C++ 클래스 > 프로젝트명 폴더 아래에도 C++로 생성한 클래스가 나타나게 됩니다.
클래스 코드 구조 분석
언리얼 엔진에서 C++ 클래스를 새로 만들면, 일반적으로 헤더(.h)와 구현(.cpp)파일이 한 쌍으로 자동 생성됩니다.
여기에서 헤더와 구현부의 구조와 각 부분의 역할을 살펴보겠습니다.
.h
헤더의 상단 코드는 다음과 같습니다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
#pragma once는 이 헤더 파일이 여러번 포함되더라도, 컴파일 시 단 한 번만 처리하도록 해주는 지시어입니다.
#include "CoreMinimal.h"은 언리얼 엔진에서 자주 사용하는 기본 타입(FString,TArray 등)과 매크로(UE_LOG등), 각종 유틸 함수들이 정의되어 있습니다.
#include "Item.generated.h"은 언리얼 엔진의 리플렉션 시스템에서 필요한 코드를 자동 생성하기 위한 매크로입니다.
헤더의 클래스 선언부 코드는 다음과 같습니다.
UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
GENERATED_BODY()
public:
// 생성자
AItem();
protected:
// 액터가 월드에 배치된 후 시작시 한 번만 호출
virtual void BeginPlay() override;
public:
// 매 프레임마다 자동으로 호출
virtual void Tick(float DeltaTime) override;
};
UCLASS()는 이 클래스를 언리얼 엔진의 리플렉션 시스템에서 인식하도록 하는 매크로입니다.
언리얼 에디터에서 이 클래스를 블루프린트로 확장할 수 있게 하고, 에디터의 여러 기능과 연동하도록 합니다.
AItem : public AActor 부분은 AActor를 상속 받아 AItem를 정의한다는 의미입니다.
AItem은 Actor 계열이라는 의미에서 접두사 A가 붙습니다.
언리얼 엔진에서 클래스 이름에 접두사를 붙이는 컨벤션에 의해 붙습니다.
언리얼 엔진 코딩 표준/컨벤션
SPARTAPROJECT_API는 이 클래스를 모듈(여기서는 SpartaProject) 외부로 Export하기 위한 매크로입니다.
DLL 등으로 빌드할 때 필요한 선언입니다.
GENERATED_BODY()는 UCLASS()와 짝을 이루어, 엔진 리플렉션에 필요한 코드를 자동으로 생성해주는 매크로입니다.
AItem()는 생성자로 Actor객체가 메모리에 생성될 때 한 번 호출되며, 월드에 배치되기 전 단계일 수 있습니다.
BeginPlay()는 액터가 월드에 완전히 배치된 뒤, 게임이 플레이 상태로 시작 할 때 한 번 호출 됩니다.
Tick(float DeltaTime)은 매 프레임마다 자동으로 불리며, 주로 매 프레임 단위의 업데이트가 필요한 로직이 들어갑니다.
.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);
}
#include "Item.h"는 헤더 파일을 포함하는데, 다른 헤더 파일보다 가장 우선되어야 합니다.
그렇지 않을 경우 언리얼의 자동 생성 매크로(리플렉션)의 순서가 뒤섞여 컴파일 에러가 날 수 있습니다.
생성자 AItem()를 포함한 BeginPlay()와 Tick(float DeltaTime)같은 라이프사이클 관련 함수에서 구현 로직을 자유롭게 추가할 수 있습니다.
댓글남기기