1. 프로그래밍 환경을 편리하게 만들어줄 매크로를 설정하고,
이를 사용해 게임에서 액터가 어떻게 생성되고, 액터에서 어떤 이벤트가 발생하는지 확인해 본다.
2. 로직을 구현해 움직임을 부여하기 / 로직 없이 무브먼트 컴포넌트로 움직임 부여하기 학습
<1>. 로깅 환경의 설정
움직이는 액터를 제작하려면 액터의 생성 과정을 알아야 함 → 중간중간 로그를 띄우게 하여 프로세스를 엿볼 수 있다.
<1> - 1. 출력 로그 윈도우 : 'UE_LOG' - (출력 로그에서 확인 가능)
UE_LOG(카테고리, 로깅 수준, 형식 문자열, 인자... )
- 카테고리 : 로그를 분류하기 위해
- 로깅 수준 : 에러(Error) = 빨간색, 경고(Warning) = 노란색, 메시지(Log) = 흰색
→ 에디터의 출력 로그 윈도우에는 필터 기능이 있어서, 원하는 로깅 수준 / 카테고리만 볼 수 있다.
- 형식 문자열 : printf 함수랑 비슷한 기능. / 문자열을 관리하는 기본 클래스는 FString. FString 변수에서 문자열 정보를 얻어오려면 반드시 * 연산자를 앞에 지정해줘야 함.
FString::Printf(TEXT("Actor Name : %s, ID : %d, Location X : %.3f"), *GetName(), ID,
GetActorLocation().X);
기존의 다양한 로그 카테고리가 있지만, 우리가 직접 로그 카테고리를 선언해 보자. → 언리얼 엔진은 직접 로그 카테고리를 선언하기 위해 2 개의 매크로를 제공한다 → 하나는 헤더파일, 하나는 소스 파일 위에 선언한다.
※해당 로그 매크로를 'ArenaBattle.h'에 선언하고 모듈의 모든 헤더들이 이 헤더를 참조하도록 구성.
//ArenaBattle.h
#include "EngineMinimal.h"
DECLARE_LOG_CATEGORY_EXTERN(ArenaBattle, Log, All);
//ArenaBattle.cpp
#include "ArenaBattle.h"
#include "Modules/ModuleManager.h"
DEFINE_LOG_CATEGORY(ArenaBattle);
...
분수대 액터 선언(Fountain.h)에서도 "EngineMinimal.h" 대신 "ArenaBattle.h"을 참조한다.
게임이 시작되고 가장 먼저 실행되는 BeginPlay 함수에 로그를 출력하여 보자.
//Fountain.cpp
void AFountain::BeginPlay()
{
Super::BeginPlay();
UE_LOG(ArenaBattle, Warning, TEXT("Actor Name : %s, ID : %d, Location X : %.3f"),
*GetName(), ID, GetActorLocation().X);
...
}
→ 현재 배치된 분수대 액터의 수만큼 로그가 출력되는 것을 볼 수 있다.
<2>. 어설션 : 반드시 확인하고 넘어가야 하는 점검 코드 (가벼운 경고 = ensure)
<3>. 액터의 주요 이벤트 함수
※이벤트 함수 : 언리얼 엔진에 의해 자동으로 호출되는 중요한 함수
- PostInitializeComponents : 액터의 모든 컴포넌트 세팅이 완료된 후에 호출
- BeginPlay : 게임에 참여할 때
- Tick : 매 프레임마다 호출
- EndPlay : 액터가 게임에서 퇴장할 때 호출
<4>. 움직이는 액터의 설계 : Tick 함수를 사용해 액터의 움직임을 구현하기
회전할 각속도의 값을 변수로 지정 → 에디터에서 편집할 수 있게 UPROPERTY에 EditAnywhere 추가 → 객체 지향 언어 설계의 중요한 원칙인 '데이터 은닉'을 위해 private로 선언 → !!! 그럼 에디터에서 값을 변경할 수 없음 → UPROPERTY 매크로에 AllowPrivateAccess라는 META 키워드 추가 → 편집함과 동시에 데이터 은닉 가능
private:
UPROPERTY(EditAnywhere, Category=Stat, Meta = (AllowPrivateAccess = true))
float RotateSpeed;
RotateSpeed 속성의 기본값을 생성자에서 초기화시킴 → Tick함수에는 AddActorLocalRotation 함수를 이용해 틱마다 회전하도록 함.
//Fountain.cpp
AFountain::AFountain()
{
RotateSpeed = 30.0f;
}
void AFountain::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
AddActorLocalRotation(FRotator(0.0f, RotateSpeed * DeltaTime, 0.0f));
}
- Pitch = Y축 회전
- Yaw = Z축 회전
- Roll = X축 회전
<5>. 무브먼트 컴포넌트의 활용
※ 무브먼트 컴포넌트 : 액터와 움직임이라는 요소를 분리해 별도로 관리하는 프레임워크.
위에서는 Tick함수를 썼지만, 무브먼트 컴포넌트를 사용하면 쓰지 않아도 된다.
-무브먼트 컴포넌트의 종류
- FloatingPawnMovement : 중력의 영향을 받지 않는 움직임.
- RotatingMovement : 지정한 속도로 액터 회전
- InterpMovement : 지정한 위치로 액터 이동
- ProjectileMovement : 중력의 영향을 받아 포물선을 그리는 발사체. ex)총알, 미사일
//Fountain.h
#include "GameFramework/RotatingMovementComponent.h" //무브먼트 컴포넌트 가져오기
class ARENABATTLE_API Fountain : public AActor
{
...
UPROPERTY(VisibleAnywhere)
URotatingMovementComponent* Movement;
...
}
!!Tick 기능을 제거함.
//Fountain.cpp
AFountain::AFountain()
{
PrimaryActorTick.bCanEverTick = false; //Tick 기능 제거하기!!!
...
Movement = CreateDefaultSubobject<URotatingMovementComponent>(TEXT("MOVEMENT"));
...
Movement->RotationRate = FRotator(0.0f, RotateSpeed, 0.0f);
}
<6>. 프로젝트의 재구성
액터 추가는 쉽게 할 수 있지만 액터 제거 메뉴는 없다. 수동으로 제거하는 법을 알아보자
- .vs, Binaries, Interdediate, ArenaBattle.sln 파일을 제거한다.
- 게임 프로젝트의 Source 폴더 내에 위치한 ArenaBattle 폴더에 있는 Fountain.h와 Fountain.cpp 파일을 삭제한다. 이 때, 반드시 탐색기에서 관련 파일을 제거해야 한다.
- 게임 프로젝트의 uproject 파일을 우클릭하고 Generate Visual Studio project files 메뉴를 선택해 비주얼 스튜디오 프로젝트를 재생성한다.
'게임 개발 > 이득우의 언리얼 C++' 카테고리의 다른 글
[이득우의 언리얼 C++ 게임개발의 정석] #7. 애니메이션 시스템의 설계 (0) | 2024.06.17 |
---|---|
[이득우의 언리얼 C++ 게임개발의 정석] #6. 캐릭터의 제작과 컨트롤 (0) | 2024.06.13 |
[이득우의 언리얼 C++ 게임개발의 정석] #5. 폰의 제작과 조작 (0) | 2024.06.10 |
[이득우의 언리얼 C++ 게임개발의 정석] #4. 게임플레이 프레임워크 (0) | 2024.06.10 |
[이득우의 언리얼 C++ 게임개발의 정석] #2. 액터의 설계 (0) | 2024.06.07 |