게임플레이 디버거는 런타임에 실시간으로 게임플레이 데이터를 분석하고 감시할 수 있도록 해주는 툴입니다.
심지어 리플리케이션을 사용하는 네트워킹 게임 내 클라이언트에서도 가능합니다.
에디터에서 플레이, 에디터에서 시뮬레이트, 독립형 게임 세션에서도 잘 돌아가며, 모든 데이터가 게임 뷰포트 위에 겹쳐 표시됩니다. 게임 전용 데이터의 디버깅을 가능하게 하기 위해 확장시킬 수 있는 프레임워크도 제공됩니다.
게임플레이 디버거로 뷰포트에 표시할 수 있는 내용은 다음과 같습니다.
- Pawn에서의 기본 데이터
- AI 컨트롤러에서의 기본 데이터
- 비헤이비어 트리 및 블랙보드 관련 데이터
- 실행된 인바이런먼트 쿼리(EQS) 관련 데이터
- 인지 시스템에서의 데이터
- 플레이어 또는 선택된 Pawn 주변 내비메시에 링크나 영역같은 디테일
보통 데이터 양이 많아서 GDT(게임플레이 디버그 툴)는 카테고리 별로 화면에 표시되는 정보 양을 제한합니다.
활성화된 카테고리에서의 데이터만 리플리케이트되어 리플리케이션 채널의 대역폭을 절약합니다.
여기서 카테고리는 5개의 기본 카테고리를 의미합니다.
위 사진은 5개의 기본 카테고리입니다.
NavMesh, Basic, Behavior(비헤이비어 트리), EQS(인바이런먼트 쿼리 시스템), Perception(인지 시스템)들이 존재합니다.
이러한 카테고리들을 활성화 또는 비활성화 하여서 뷰포트에 띄울 데이터를 선택할 수 있습니다.
위 사진은 인지 시스템을 제외한 4가지 기본 카테고리들을 활성화시킨 뷰포트의 사진입니다.
게임플레이 디버거는 기본적으로 "(어포스트로피) 키로 활성화하거나 비활성화할 수 있습니다. 키 바인딩은 파일에서 설정하며, 쉽게 변경 가능합니다.
디버깅을 위해 적을 선택하려면, 화면상의 적을 가리키는 동안 키를 누르면 됩니다. 그리고 숫자 키보드를 사용하여 가시 카테고리 사이를 전환합니다.
또한, 게임플레이 디버거 모듈을 활성화시켜 사용하기 위해서는 프로젝트의 종속성 모듈에 게임플레이 디버거 모듈을 추가시켜야 합니다.
1. 게임플레이 디버거 에디터에서 설정하는 법
에디터 내 작업시 GDT는 PIE 또는 SIE에서 사용할 수 있습니다. 바인딩된 키 또는 EnableGDT 치트는 PIE에서 GDT를 활성화시키는데 사용될 수 있습니다. 시뮬레이션 모드는 PIE와 약간 다른데, 디버그 툴 활성화를 위해서는 Debug AI 표시 플래그를 켜줄 필요가 있습니다.
그리고 시뮬레이트에서 보이는 카테고리를 변경하는 옵션도 있습니다.
GameplayDebuggingReplicator 액터가 사용되는데, 이 액터는 씬 아웃라이너에서 찾을 수 있으며, 그 프로퍼티가 GDT 제어에 사용됩니다.
2. 게임플레이 디버거 확장
게임플레이 디버거는 C++ 코드로만 확장이 가능합니다. 블루프린트 프로젝트의 경우 있는 그대로만 사용 가능하여 현재로서는 기본적인 디버그 정보만 표시됩니다. 게임플레이 디버거를 확장시켜 게임 특정 데이터를 수집하고 표시하는 것은 매우 쉽습니다.
UGameplayDebuggingComponent 클래스와 AGameplayDebuggingHUDComponent 클래스에서 상속된 커스텀 클래스가 필요합니다. UGameplayDebuggingComponent 클래스는 데이터 수집 및 나중에는 리플리케이션에도 사용되며, AGameplayDebuggingHUDComponent 클래스는 수집된 데이터 전부를 화면에 표시하는데 사용됩니다.
GDTComponent.h
#pragma once
#include "GameplayDebuggingComponent.h"
#include "GDTComponent.generated.h"
UCLASS()
class UGDTComponent : public UGameplayDebuggingComponent
{
public:
GENERATED_UCLASS_BODY()
virtual void CollectBasicData() override;
UPROPERTY(Replicated)
float TestData; //custom data replicated to clients
};
GDTComponent.cpp
#include "MyGameProject.h"
#include "GameplayDebuggingComponent.h"
#include "GDTComponent.h"
UGDTComponent::UGDTComponent(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP) { }
void UGDTComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty> &OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps( OutLifetimeProps );
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
DOREPLIFETIME( UGDTComponent, TestData);
#endif
}
void UGDTComponent::CollectBasicData()
{
Super::CollectBasicData();
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
TestData= FMath::RandRange(2.75, 8.25); //collect data and store it
#endif
}
위 예제 코드는 게임 전용 데이터를 수집하는 간단한 클래스를 구현한 것입니다.
GDTHUDComponent.h
#pragma once
#include "GameplayDebuggingHUDComponent.h"
#include "GDTHUDComponent.generated.h"
UCLASS(notplaceable)
class AGDTHUDComponent: public AGameplayDebuggingHUDComponent
{
GENERATED_UCLASS_BODY()
protected:
virtual void DrawBasicData(APlayerController* PC, class UGameplayDebuggingComponent *DebugComponent) override;
};
GDTHUDComponent.cpp
#include "MyGameProject.h"
#include "GDTComponent.h"
#include "GDTHUDComponent.h"
AGDTHUDComponent::AGDTHUDComponent(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
}
void AGDTHUDComponent::DrawBasicData(APlayerController* PC, class UGameplayDebuggingComponent *DebugComponent)
{
Super::DrawBasicData(PC, DebugComponent);
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
const UGDTComponent* MyComp = Cast<UGDTComponent>(DebugComponent);
if (MyComp)
{
PrintString(DefaultContext, FString::Printf(TEXT("{white}Test data: {red}%f\n"), MyComp->TestData));
}
#endif
}
위 예제 코드를 통해 구현된 클래스는 새로운 게임 전용 데이터를 화면에 표시하는데 사용됩니다.
게임플레이 디버거는 새로운 클래스에 대해 알 필요가 있으며, 그 정보는 DefaultEngine.ini 환경설정 파일에 설정 가능합니다.
DefaultEngine.ini
[/Script/GameplayDebugger.GameplayDebuggingReplicator]
DebugComponentClassName="/Script/MyGameProject.GDTComponent"
DebugComponentHUDClassName="/Script/MyGameProject.GDTHUDComponent"
'언리얼 C++ 프로그래밍' 카테고리의 다른 글
[언리얼 C++] 언리얼 프로젝트(애셋, 레벨, 액터) (0) | 2021.08.02 |
---|---|
[언리얼 C++] 프로그래밍 서브시스템 (0) | 2021.08.01 |
[언리얼 C++] 구조체 선언 및 정의 (1) | 2021.07.30 |
[언리얼 C++] 프로퍼티 선언 (0) | 2021.07.29 |
[언리얼 C++] 인터페이스 클래스 (0) | 2021.07.28 |