초보 코린이의 성장 일지

UE4 DrawDebugLine 본문

언리얼

UE4 DrawDebugLine

코오린이 2023. 4. 4. 12:27

디버그 플러그인을 사용하여, 플레이어 정보, 플레이어 전방에 있는 객체, Debug Actor 3가지를 띄어보도록 할 것이다.

 

 

 

public FGameplayDebuggerCategory 함수
FExampleDubuggerCategory.h

1. 화면상에 그려지기 위해 상속받은 부모로 들어가서 함수를 오버라이드 해서 사용한다.

 

더보기
#pragma once

#include "CoreMinimal.h"
#include "GameplayDebuggerCategory.h"

class EXAMPLE_API FExampleDubuggerCategory
	: public FGameplayDebuggerCategory // 사용하기 위해 상속
{

public:
// 실제로 그려주는 함수
	void DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext) override;

private:
	struct  FCategoryData
	{ 
		bool bDraw = false; // 그릴지 말지 체크
		FString Name;
		FVector Location; 
		FVector Forward;
	};

private:
	// 저장할 정보
	FCategoryData PlayerPawnData;
	FCategoryData ForwardActorData;
	FCategoryData DebugActorData;

private:
	float TraceDistance = 500;
#include "ExampleDubuggerCategory.h"
#include "CanvasItem.h"
#include "DrawDebugHelpers.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerController.h"

FExampleDubuggerCategory::FExampleDubuggerCategory()
{
	// DebugActor을 꺼줘서 전부 보여줘라
	bShowOnlyWithDebugActor = false;
}

FExampleDubuggerCategory::~FExampleDubuggerCategory()
{

}

void FExampleDubuggerCategory::CollectData(APlayerController* OwnerPC, AActor* DebugActor)
{
	// 플레이어는 Owner안에 Pawn을 뜻함
	ACharacter* player = OwnerPC->GetPawn<ACharacter>();
	if (player == nullptr) return;

	// Player
	{
		// 플레이어 정보 저장, 플레이어는 맵상에 항상있으므로 계속 출력
		PlayerPawnData.bDraw = true;
		PlayerPawnData.Name = player->GetName();
		PlayerPawnData.Location = player->GetActorLocation();
		PlayerPawnData.Forward = player->GetActorForwardVector();
	}

	// Forward Actor
	{
		FHitResult hitResult;

		FVector start = PlayerPawnData.Location;
		FVector end = start + player->GetActorForwardVector() * TraceDistance;

		FCollisionQueryParams params;
		params.AddIgnoredActor(player); // 충돌에서 플레이어는 제외

		// Trace도 World안에 존재하므로 LineTraceSingleByChannel 사용, ECC_Visibility : 보이는거 다 추적
		player->GetWorld()->LineTraceSingleByChannel(hitResult, start, end, ECollisionChannel::ECC_Visibility, params);

		if (hitResult.bBlockingHit) // hit시 보여주기
		{
			ForwardActorData.bDraw = true;
			ForwardActorData.Name = hitResult.GetActor()->GetName();
			ForwardActorData.Location = hitResult.GetActor()->GetActorLocation();
			ForwardActorData.Forward = hitResult.GetActor()->GetActorForwardVector();
		}
	}

	// DebugActor
	if (!!DebugActor) // 마우스로 선택했을시에만 출력되도록 선택 안한 상태면 출력 x
	{
		DebugActorData.bDraw = true;
		DebugActorData.Name = DebugActor->GetName();
		DebugActorData.Location = DebugActor->GetActorLocation();
		DebugActorData.Forward = DebugActor->GetActorForwardVector();
	}

}

void FExampleDubuggerCategory::DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext)
{
	// 화면사엥 그려지기
	FGameplayDebuggerCategory::DrawData(OwnerPC, CanvasContext);

	FVector start = PlayerPawnData.Location;
	FVector end = start + PlayerPawnData.Forward * TraceDistance;

	DrawDebugLine(OwnerPC->GetWorld(), start, end, FColor::Red);

1. 플레이어, LineTrace, Actor 3가지 출력을 위해 작성.

 

1. 아직은 Trace만 출력되는걸 알 수 있다.

2. 변수로 받아온 객체들에 정보를 아직 담아준 상태가 아니기 때문에 다른건 출력이 되질 않는다.

 

더보기
void FExampleDubuggerCategory::DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext)
{
	// Canvas 생성자 : 어디부터 출력할지, 2D형태, 사이즈, 색, 
	FCanvasTileItem item(FVector2D(10, 10), FVector2D(300, 215), FLinearColor(0, 0, 0, 0.25f));
	item.BlendMode = ESimpleElementBlendMode::SE_BLEND_AlphaBlend; // 반투명으로 그리기
	CanvasContext.DrawItem(item, CanvasContext.CursorX, CanvasContext.CursorY); // 아이템 가지고 x, y 위치로 그려주기

	// 정보들 출력
	CanvasContext.Printf(FColor::Green, L"  -- Player Pawn --");
	CanvasContext.Printf(FColor::White, L"  Name : %s", *PlayerPawnData.Name);
	CanvasContext.Printf(FColor::White, L"  Location : %s", *PlayerPawnData.Location.ToString());
	CanvasContext.Printf(FColor::White, L"  Forward : %s", *PlayerPawnData.Forward.ToString());
	CanvasContext.Printf(FColor::White, L"");

	if (ForwardActorData.bDraw)
	{
		CanvasContext.Printf(FColor::Green, L"  -- Forward Actor --");
		CanvasContext.Printf(FColor::White, L"  Name : %s", *ForwardActorData.Name);
		CanvasContext.Printf(FColor::White, L"  Location : %s", *ForwardActorData.Location.ToString());
		CanvasContext.Printf(FColor::White, L"  Forward : %s", *ForwardActorData.Forward.ToString());
		CanvasContext.Printf(FColor::White, L"");
	}

	if (DebugActorData.bDraw)
	{
		CanvasContext.Printf(FColor::Green, L"  -- Select Actor --");
		CanvasContext.Printf(FColor::White, L"  Name : %s", *DebugActorData.Name);
		CanvasContext.Printf(FColor::White, L"  Location : %s", *DebugActorData.Location.ToString());
		CanvasContext.Printf(FColor::White, L"  Forward : %s", *DebugActorData.Forward.ToString());
	}
}

1. Debug 출력이 보여진다.

 

1. 플레이어 자신 정보.

1. Trace에 걸린 객체 정보

3. 빙의를 푼 상태로 Actor 선택시 보이는 정보.

 

1. 언리얼안에 ` 표시를 누르면 cmd 콘솔 커멘드 명령창이 나오게 된다. 이걸 사용하여 안에서도 명령을 내릴 수 있다.

2. 폴더 Example에 클래스 생성.

 

더보기
#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class FExampleModule : public IModuleInterface
{
public:
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;

private:
	// 콘솔 커멘드
	TSharedPtr<class FExampleConsoleCommand> ConsoleCommand;

};
#include "ExampleModule.h"
#include "ExampleDubuggerCategory.h"
#include "ExampleConsoleCommand.h"

#include "GameplayDebugger.h" // 언리얼 헤더

#define LOCTEXT_NAMESPACE "FExampleModule"

IMPLEMENT_MODULE(FExampleModule, Example)

void FExampleModule::StartupModule()
{
	// Console Command
	{
		// 객체 동적할당 MakeShareable
		ConsoleCommand = MakeShareable(new FExampleConsoleCommand());
	}
	
}

void FExampleModule::ShutdownModule()
{
	// 항상 할당을 했으면, 제거되어야 하는게 있는지 반드시 확인해줘야한다.
	// 그렇지 않으면 에디터상에 항상 남아있는다.
	if (IGameplayDebugger::IsAvailable())
		IGameplayDebugger::Get().UnregisterCategory("Example"); // 카테고리에서 해제

	// 스마트포인터는 자동제거가 되지만, 혹시 모르기 때문에 Reset로 제거해준다.
	if (ConsoleCommand.IsValid())
		ConsoleCommand.Reset();
}

#undef LOCTEXT_NAMESPACE

1. 콘솔 커멘드를 만들기 위한 기본적인 세팅.

더보기
#pragma once

#include "CoreMinimal.h"

class EXAMPLE_API FExampleConsoleCommand
{
public:
	FExampleConsoleCommand();
	~FExampleConsoleCommand();

private:
	// I가 붙었지만 클래스가 아닌 구조체이다.
	struct IConsoleCommand* Command;

};
#include "ExampleConsoleCommand.h"
#include "HAL/IConsoleManager.h"

FExampleConsoleCommand::FExampleConsoleCommand()
{

}

FExampleConsoleCommand::~FExampleConsoleCommand()
{

}

1. 구조체라서 전방선언을 해준다.

2. 아직은 설명이 필요하고, 코드는 나중에 채워나갈 것이다.

1. 엔진에서 다룰때 HAL, RHI를 많이 보게 될 것이다. 이 둘은 하나의 계층사이에 묶여있다.

2. HAL은 그래픽을 출력해주기 위한 레이어를 뜻하며. 프로그래밍에 있어 다양한 그래픽 카드를 기준으로 기능을 만들어 줄때 모든걸 고려할수가 없다. 그래서 하나의 가상계층인 HAL 계층을 만들어준다. 중간사이에서 어떤 하드웨어든지 언리얼 쪽에서 그 과정을 담아 처리할수 있도록 해주는 계층이 된다. 

3. 그래서 프로그래머들은 RHI (랜더 하드웨어 인터페이스) 작업을 하게된다.

4. 명령이 내려지면 RHI로 들어오게 되고, HAL이 실제로 구현한 하드웨어를 따라 RHI가 하드웨어를 선택을해준다.

5. RHI 하나당 HAL도 하나씩 존재한다고 생각하면 된다.

6. 그래서 어떠한 하드웨어가 있던지 신경을 쓸 이유가 사라진다. 가상에 계층에서 모든걸 전환할것이기 때문.

 

https://www.youtube.com/watch?v=jOd76hi6420 

 

'언리얼' 카테고리의 다른 글

UE4 StaticMesh  (0) 2023.04.06
UE4 Console, Command  (0) 2023.04.05
UE4 Slate UI, Plug In  (0) 2023.04.03
UE4 FPS IK, Pistol  (0) 2023.04.01
UE4 FPS Pistol  (0) 2023.03.31
Comments