컴포넌트란 성격일수도 있고 외형일수도 있고 재능일수도 있다.
존재만 하는 단순 루트 컴포넌트만 있을 수도 있고 메시나 오디오 또는 이펙트 등의 느낄 수 있는 컴포넌트도 있다.
컴포넌트를 붙여주면 액터에게 개성이 생기고 쓸모가 생기기 시작한다.
허전한 것엔 컴포넌트를 붙여 쓸모있게 유용하게 만들어주자.
1. UObject
- 모든 클래스의 최상위 부모. 스스로 월드에 배치될 수 없다. 화면에 보이지 않는 추상적인 부분을 처리한다.
2. AActor
- UObject를 확장(상속)한 클래스. 배치가능한 모든 것들을 말한다. 연극으로 치면 무대에서 관객들에게 보여지고 들려지는 모든 것일 수 있겠다.
3. Actor 기본 헤더
- 언리얼엔진 에디터 내에서 클래스 생성을 실행하면 기본 프레임이 갖춰진 헤더파일과 소스파일이 생성된다. 그리고 헤더 또한 기본으로 입력되는데 기본 헤더는 다음과 같다.
#include "CoreMinimal.h" // 로그함수 및 언리얼 기본 타입들이 포함된 헤더
#include "GameFramework/Actor.h" // 상속받은 Actor클래스에 대한 정보가 담긴 헤더
#include "MyActor.generated.h" // 리플렉션 시스템 등을 포함. 항상 마지막에 있어야 한다.
4. 클래스별 접두어(예시)
- Actor : A (AActor)
- Object : U (UObject)
- 구조체 : F (FVector)
- Enum : E (EEndPlayReason)
5. 컴포넌트 만들기
//======헤더파일에서
UCLASS()
//^해당 클래스를 리플렉스 시스템에 등록하는 매크로
class MYPROJECT_API AMyActor : public AActor
{ // ^프로젝트명_API ^클래스명 ^액터 클래스 상속
GENERATED_BODY()
// ^UCLASS와 쌍으로 리플렉션 데이터를 자동으로 생성하는 매크로
public:
AMyActor();
// ^ 생성자
protected:
USceneComponent* (SceneRoot);
//^씬 컴포넌트 포인터 ^루트로 지정할 컴포넌트 이름
UStaticMeshComponenet* (StaticMeshComp);
//^스태틱메시 컴포넌트 포인터 ^스태틱메시 컴포넌트 이름
};
//======소스파일에서
AMyActor::AMyActor()
{//^클래스명 ^생성자명
SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
//^헤더 내 선언변수 ^컴포넌트 생성 함수 ^컴포넌트 타입 ^컴포넌트 이름
SetRootComponent(SceneRoot);
//^루트 지정 함수 ^지정할 컴포넌트 이름
StaticMeshComp = CreateDefualtSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
// 1줄과 동일구조
StaticMeshComp->SetAttachment(SceneRoot);
//^붙일 컴포넌트 ^컴포넌트 붙이기 ^목표 컴포넌트 이름
//위 컴포넌트에 넣을 메쉬선언
static CostructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("Game/에디터 내 경로/MyMesh.MyMesh"));
//^에셋 리소스를 찾아서 로드하는 클래스 ^에셋 타입 ^오브젝트변수이름 ^로드할 에셋 주소
if(MeshAsset.Succeeded())
{// ^로드 성공 확인
StaticMeshComp->SetStaticMesh(MeshAsset.Object);
} //^에셋을 넣을 컴포넌트 ^스태틱메시를 넣어주는 함수(메시 이름과 FObjectFinder로 찾은 오브젝트의 포인터)
}
- 루트 컴포넌트를 만들어주고 붙일 컴포넌트를 생성해 붙인 뒤, 컴포넌트에 넣을 에셋 등을 적용해주는 순서다.
6. 커스텀 로그 선언
//====헤더파일 상단
DECLARE_LOG_CATEGORY_EXTERN(LogTemp, Warning, All);
//^로그명, 로그최소수준, 로그최대수준
//====소스파일 상단
DEFINE_LOG_CATEGORY(LogTemp)
//^로그명
//로그 출력
UE_LOG(LogTemp, Warning, TEXT("Log Message");
//^로그함수, 로그명, 로그수준, 로그 메시지내용
- 로그 카테고리명 과 로그 수준을 직접 만들 수 있다.
- 로그 카테고리는 보통 별도의 헤더로 관리하는 경우가 많다.
7. 액터 라이프사이클 함수
- 라이프 사이클 : 액터가 소(Spawn)되었다가 소멸(Destroy)되는 과정의 주기
//-탄생단계
AMyActor();
// 생성자. 오브젝트가 메모리에 생성. 딱한번 호출. 액터 생성 전 여러가지 초기화 단계
PostInitializeComponents();
// 액터 컴포넌트들이 초기화된 직후 자동 호출. 컴포넌트끼리 월드 등장 전 데이터주고받기 또는 상호작용이 필요할때 유용
BeginPlay();
// 배치(Spwan) 직후 (플레이 시작)
//-생단계
Tick(float DelaTime);
// 매 프레임마다 호출
//-죽음단계
Destroyed();
//삭제가 되기 직전 호출. 리소스 정리할 때.
EndPlay(const EEndPlayReason::Type EndPlayReason);
//게임 종료, 파괴(Destroyed()), 레벨 전환
- 부모클래스에 상속되어있는 기능들이기 때문에 Super::(함수명)으로 사용한다.
8. Super::
//헤더파일에서
virtual void BeginPlay();
//소스파일에서
void MyActor::BeginPlay()
{
Super::BeginPlay();
}
- Super::는 부모클래스로부터 해당 기능을 받아오는 기능이다.
BeginPlay를 예로 들자면 아버지가 아들에게 "시작!" 하고 신호를 알려주면 그 신호에 맞춰 작업을 시작할 수 있다.
Destroyed를 예로 들자면 아버지가 아들에게 "이렇게 삭제하는거란다"하고 알려주면 아들이 그 방법대로 삭제하는 것이다.
그 전까진 항상 에디터를 이용해서만 액터를 생성해봤었는데 오늘 처음으로 C++코드를 이용해서 제대로 된 액터를 구현해봤다.
블루프린트를 이용한 액터생성작업이 저렴하고 사기 쉽지만 어딘가 불편한 기성복이라면
C++을 이용한 액터생성작업은 비싸고 맞추기 어렵지만 몸에 딱 맞출 수 있는 맞춤정장의 느낌인 것 같다.
그만큼 c++을 이용하면 디테일한 개성이 있는 액터를 만들어 낼 수 있을 것 같다.
'게임 개발 공부 > 언리얼엔진' 카테고리의 다른 글
| UE5 | C++ 개발 - 움직이는 액터 제작 (3) | 2025.01.23 |
|---|---|
| UE5 | C++개발학습 - 리플렉션 시스템 (0) | 2025.01.21 |
| UE5 - Git lfs (0) | 2025.01.07 |
| 언리얼 엔진 5 - 캐릭터 애니메이션 (2) | 2024.12.20 |
| 언리얼 엔진 5 - 블루프린트를 이용한 플레이어 캐릭터 무브먼트 작성 (3) | 2024.12.19 |