본문 바로가기
언리얼 C++ 게임 개발의 정석/1. 개발 환경 셋팅

1.2 엑터의 설계

by ftftgop3 2024. 1. 27.

액터

콘텐츠의 구성의 최소 단위의 물체

 

엑터의 구성 요소

이름 : 액터 명칭

유형 : 게임 플레이 수행할 액터의 의미, 액터의 클래스 이름

트랜스 폼 : 월드에 존재 , 트랜스 폼 부여

프로퍼티 : 액터의 속성 값

게임 로직 : 구제적인 동작 블루프린트, C++ 지원

 

레벨

플레이어에게 주어지는 스테이지 

레벨은 월드에 배치된 액터들의 집합 

레벨에서 플레이 시 레벨을 구성하는 미리 만들어진 엑터는 흰색, 새롭게 생성하는 액터는 노락색으로 표시

 

컴포넌트

엑터에 컴포넌트를 추가 해서 시각적 기능, 물리적 기능, 움직임 등을 부여

스태틱 메시 컴포넌트 : 배경 물체 

스켈레탈 메시 컴포넌트 : 애니메이션 정보가 있는 모델링

무브 먼트 컴포넌트 : 특정한 움직임 부여 등 

각 컴포넌트에는 고유한 특징이 있고 그걸 활용 해 여러 엑터를 설계 한다

 

루트 컴포넌트

한 엑터에 여러 컴포넌트를 가질 수 있지만 대표하는 하나 컴포넌트를 무조건 지정

 

 

 

C++ 헤더 언리얼 오브젝트 클래스 예시

매개변수 매크로 : UPROPERTY(VisibleAnywhere)

자동으로 메모리 관리, 언리얼 오브젝트만 사용 

에디터 창에서 데이터 수정 및 편집 가

 

#include "Fountain.generated.h"
컴파일 전에 엔진에서 언리얼 헤드 툴 이라는 도구 사용해 클래스 선언 분석 
환경에 필요한 별도의 파일을 생성 꼭 include 해야 한다

 

UCLASS()
class ARENABATTLE_API AFountain : public AActor

언리얼 오브젝트를 매크로 선언
클래스 이름 접두사 A : 엑터 클래스 
클래스 이름 접두사 U : 엑터가 아닌 클래스

 

ARENABATTLE_API 모듈명 _API 선언해 DLL 내 클래스 정보를 외부에 공개를 결정
이 키워드가 없으면 다른 모듈에서 해당 객체에 접근이 불가능 하다

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "ArenaBattle.h"
#include "GameFramework/Actor.h"
#include "Fountain.generated.h"
//컴파일 전에 엔진에서 언리얼 헤드 툴 이라는 도구 사용해 클래스 선언 분석 
//환경에 필요한 별도의 파일을 생성 꼭 include 해야 한다

//언리얼 오브젝트를 매크로 선언
//클래스 이름 접두사 A : 엑터 클래스 
//클래스 이름 접두사 U : 엑터가 아닌 클래스
UCLASS()
class ARENABATTLE_API AFountain : public AActor
{
//ARENABATTLE_API 모듈명 _API 선언해 DLL 내 클래스 정보를 외부에 공개를 결정
//이 키워드가 없으면 다른 모듈에서 해당 객체에 접근이 불가능 하다
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AFountain();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	UPROPERTY(VisibleAnywhere)
	UStaticMeshComponent *Body;

	UPROPERTY(VisibleAnywhere)
	UStaticMeshComponent *Water;

	UPROPERTY(VisibleAnywhere)
	UPointLightComponent *Light;

	UPROPERTY(VisibleAnywhere)
	UParticleSystemComponent *Splash;

	UPROPERTY(EditAnywhere, Category=ID)
	int32 ID;
};

 

C++ CPP 언리얼 오브젝트 클래스 예시

컴포넌트 할당 new 대신 사용 CreateDefaultSubobject
컴포넌트를 구별 하기 위해 Hash 값을 생성 TEXT("name")
Body = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BODY"));

AFountain::AFountain()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	//컴포넌트 할당 new 대신 사용 CreateDefaultSubobject
    //컴포넌트를 구별 하기 위해 Hash 값을 생성 TEXT("name")
    
	Body = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BODY"));
	Water = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WATER"));
	Light = CreateDefaultSubobject<UPointLightComponent>(TEXT("LIGHT"));
	Splash = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("SPLASH"));
	//루트 컴포넌트 지정 (분수대 구조물이 대표)
	RootComponent = Body;
    //루트 컴포넌트의 자식으로 배치
	Water->SetupAttachment(Body);
	Light->SetupAttachment(Body);
	Splash->SetupAttachment(Body);
	//각 컴포넌트의 위치 배치
	Water->SetRelativeLocation(FVector(0.0f, 0.0f, 135.0f));
	Light->SetRelativeLocation(FVector(0.0f, 0.0f, 195.0f));
	Splash->SetRelativeLocation(FVector(0.0f, 0.0f, 195.0f));

	static ConstructorHelpers::FObjectFinder<UStaticMesh> SM_BODY(TEXT("/Game/InfinityBladeGrassLands/Environments/Plains/Env_Plains_Ruins/StaticMesh/SM_Plains_Castle_Fountain_01.SM_Plains_Castle_Fountain_01"));

	if (SM_BODY.Succeeded())
	{
		Body->SetStaticMesh(SM_BODY.Object);
	}

	static ConstructorHelpers::FObjectFinder<UStaticMesh> SM_WATER(TEXT("/Game/InfinityBladeGrassLands/Effects/FX_Meshes/Env/SM_Plains_Fountain_02.SM_Plains_Fountain_02"));
	
	if (SM_WATER.Succeeded())
	{
		Water->SetStaticMesh(SM_WATER.Object);
	}

	static ConstructorHelpers::FObjectFinder<UParticleSystem> PS_SPLASH(TEXT("/Game/InfinityBladeGrassLands/Effects/FX_Ambient/Water/P_Water_Fountain_Splash_Base_01.P_Water_Fountain_Splash_Base_01"));

	if (PS_SPLASH.Succeeded())
	{
		Splash->SetTemplate(PS_SPLASH.Object);
	}
}

 

핫 리로드

모듈을 컴파일 시 언리얼이 감지 해 기존의 모듈을 내리고 신규 모듈로 바꾸어 작업 수행

기존 모듈을 덮어 쓰지 않고 기존 모듈의 이름뒤에 숫자를 붙인 새로운 파일로 생성

 

객체 유형과 값 유형

바이트 : uint8, 정수 : int32, 실수 : float , 문자열 : Fstring, FName , 구조체 : FVector, FRotator, FTransform

UPROPERTY 매크로로 선언 시 초기 값 보장, int 형은 0 초기화

Category : 디테일 창에 새로운 카테고리로 변수를 수정

UPROPERTY(EditAnywhere, Category=ID)
int32 ID;

 

래퍼런스 복사로 오브젝트 경로 파악

원하는 언리얼 오브젝트를 Ctrl + C를 누르면 해당 래퍼런스 복사

[오브젝트 타입]{'폴더명/ 파일명.에셋명'}

StaticMesh'/Game/InfinityBladeGrassLands/Environments/Plains/Env_Plains_Ruins/StaticMesh/SM_Plains_Castle_Fountain_01.SM_Plains_Castle_Fountain_01'

4.19 언리얼 버전에서는 오브젝트 타입, '' 기호 제거 후 사용

원하는 오브젝트를 C++ 코드에서 애셋 로드 후 사용 가능 

Static 으로 사용 해 처음 한번만 초기화 하는것이 효율적

static ConstructorHelpers::FObjectFinder<UStaticMesh> SM_BODY(TEXT("/Game/InfinityBladeGrassLands/Environments/Plains/Env_Plains_Ruins/StaticMesh/SM_Plains_Castle_Fountain_01.SM_Plains_Castle_Fountain_01"));

if (SM_BODY.Succeeded())
{
Body->SetStaticMesh(SM_BODY.Object);
}