언리얼 엔진에서 Draw Debug는 개발자들이 런타임 동안 다른 게임 시스템이나 코드 로직의 동작을 시각화할 수 있는 기능이다. 게임 엔진에서 일어나는 일을 시각적으로 보여줌으로써 진단하기 어려운 문제나 오류를 식별하는 데 도움이 될 수 있다.

 

 

목차

     

     


     

     

    Log 출력하기

     

     


     

    CLog 수정

     

    CLog.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    
    //매크로로 치환
    #define LogLine() {  CLog::Log(__FILE__, __FUNCTION__, __LINE__);}
    #define PrintLine() {  CLog::Print(__FILE__, __FUNCTION__, __LINE__);}
    
    class U2212_03_API CLog
    {
    public:
    	static void Log(int32 InValue);
    	static void Log(float InValue);
    	static void Log(const FString& InValue);
    	static void Log(const FVector& InValue);
    	static void Log(const FRotator& InValue);
    	static void Log(const UObject* InValue);
    	static void Log(const FString& InFileName, const FString& InFuncName, int32 InLineNumber); //파일이름, 함수명, 줄번호
    
    	// InKey -1을 Default Value로 설정. InDuration(출력시간). FColor(출력색)
    	static void Print(int32 InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue);
    	static void Print(float InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue);
    	static void Print(const FString& InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue);
    	static void Print(const FVector& InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue);
    	static void Print(const FRotator& InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue);
    	static void Print(const UObject* InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue);
    	static void Print(const FString& InFileName, const FString& InFuncName, int32 InLineNumber);
    };
    • 매크로 사용
      • #define LogLine() {  CLog::Log(__FILE__, __FUNCTION__, __LINE__);}
      • #define PrintLine() {  CLog::Print(__FILE__, __FUNCTION__, __LINE__);}

     

     

    CLog.cpp

    더보기
    #include "Utilities/CLog.h"
    #include "Engine.h"
    
    DEFINE_LOG_CATEGORY_STATIC(GP, Display, All)
    
    void CLog::Log(int32 InValue)
    {
    	//GLog->Log("GP", ELogVerbosity::Display, FString::FromInt(InValue));
    	UE_LOG(GP, Display, L"%d", InValue);
    }
    
    void CLog::Log(float InValue)
    {
    	UE_LOG(GP, Display, L"%f", InValue);
    }
    
    void CLog::Log(const FString & InValue)
    {
    	UE_LOG(GP, Display, L"%s", *InValue);
    }
    
    void CLog::Log(const FVector & InValue)
    {
    	UE_LOG(GP, Display, L"%s", *InValue.ToString());
    }
    
    void CLog::Log(const FRotator & InValue)
    {
    	UE_LOG(GP, Display, L"%s", *InValue.ToString());
    }
    
    void CLog::Log(const UObject * InValue)
    {
    	FString str;
    
    	if (!!InValue)
    		str.Append(InValue->GetName());
    
    	str.Append(!!InValue ? " Not Null" : "Null");
    
    	UE_LOG(GP, Display, L"%s", *str);
    }
    
    void CLog::Log(const FString& InFileName, const FString& InFuncName, int32 InLineNumber)
    {
    	//예시 //C:\\Test\\Test.cpp    
    
    	int32 index = 0, length = 0; //지역변수는 초기화를 해주는게 좋다.
    	InFileName.FindLastChar(L'\\', index);//반대부터 찾는다. 검색은 오른쪽에서하고 index는 왼쪽에서부터 리턴한다.
    
    	length = InFileName.Len() - 1; //Index로 다루기 때문에 -1
    	FString fileName = InFileName.Right(length - index); //예시의 경우 남는부분은 Text.cpp 부분
    
    	UE_LOG(GP, Display, L"%s, %s, %d", *fileName, *InFuncName, InLineNumber);
    
    }
    
    void CLog::Print(int32 InValue, int32 InKey, float InDuration, FColor InColor)
    {
    	GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, FString::FromInt(InValue));
    }
    void CLog::Print(float InValue, int32 InKey, float InDuration, FColor InColor)
    {
    	GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, FString::SanitizeFloat(InValue));
    }
    
    void CLog::Print(const FString & InValue, int32 InKey, float InDuration, FColor InColor)
    {
    	GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, InValue);
    }
    
    void CLog::Print(const FVector & InValue, int32 InKey, float InDuration, FColor InColor)
    {
    	GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, InValue.ToString());
    }
    
    void CLog::Print(const FRotator & InValue, int32 InKey, float InDuration, FColor InColor)
    {
    	GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, InValue.ToString());
    }
    
    void CLog::Print(const UObject * InValue, int32 InKey, float InDuration, FColor InColor)
    {
    	FString str;
    
    	if (!!InValue)
    		str.Append(InValue->GetName());
    
    	str.Append(!!InValue ? " Not Null" : "Null");
    
    	GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, str);
    }
    
    void CLog::Print(const FString& InFileName, const FString& InFuncName, int32 InLineNumber)
    {
    	int32 index = 0, length = 0;
    	InFileName.FindLastChar(L'\\', index);
    
    	length = InFileName.Len() - 1;
    	FString fileName = InFileName.Right(length - index);
    
    	FString str = FString::Printf(L"%s, %s, %d", *fileName, *InFuncName, InLineNumber);
    	GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Blue, str);
    }
    • Engine.h는 굉장히 큰 파일이다. 여기서는 추가했지만 Global.h에 넣는것은 지양해야 한다. 속도가 느려진다.
    • 언리얼은 전부다 미리 컴파일된 헤더로 취급된다. 
    • SanitizeFloat()은 float를 문자열로 바꾸어준다.
    void AddOnScreenDebugMessage
    (
        uint64 Key,
        float TimeToDisplay, 
        FColor DisplayColor, 
        const FString & DebugMessage,
        bool bNewerOnTop, //계속 새로운게 위로 올라갈 것인가?
        const FVector2D & TextScale //텍스트 크기
    )
    • AddOnScreenDebugMessage()는 GEngine라는 전역객체에 있는 내장함수.

     

     

    출력로그

     

     


     

    C01_Log & BP_C01_Log

     

    C01_Log.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "C01_Log.generated.h"
    
    UCLASS()
    class U2212_03_API AC01_Log : public AActor
    {
    	GENERATED_BODY()
    	
    public:	
    	AC01_Log();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:	
    	virtual void Tick(float DeltaTime) override;
    
    private:
    	float TotalTime;
    };

     

     

    C01_Log.cpp

    더보기
    #include "02_Profiler/C01_Log.h"
    #include "Global.h"
    
    AC01_Log::AC01_Log()
    {
     	PrimaryActorTick.bCanEverTick = true;
    }
    
    void AC01_Log::BeginPlay()
    {
    	Super::BeginPlay();
    
    	CLog::Log(10);
    	CLog::Log(PI);
    	CLog::Log("C01_Log");
    	CLog::Log(GetActorLocation());
    	CLog::Log(GetActorRotation());
    	CLog::Log(this);
    
    	CLog::Log(__FILE__);
    	CLog::Log(__FUNCTION__);
    	CLog::Log(__LINE__);
    
    	CLog::Log(__FILE__, __FUNCTION__, __LINE__);
    
    	LogLine();
    
    	CLog::Print(10);
    	CLog::Print(PI);
    	CLog::Print("C01_Log");
    	CLog::Print(GetActorLocation());
    	CLog::Print(GetActorRotation());
    	CLog::Print(this);
    
    	PrintLine();
    }
    
    void AC01_Log::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	TotalTime += DeltaTime;
    	CLog::Print(TotalTime, 100); //Print(InValue, InKey); InKey값은 0보다 큰 값 사용.
    
    }

     


     

    실행화면

     

     

     


     

     

     

     

    Draw Debug

     

    언리얼 엔진에서 Draw Debug는 개발자들이 런타임 동안 다른 게임 시스템이나 코드 로직의 동작을 시각화할 수 있는 기능이다. 게임 엔진에서 일어나는 일을 시각적으로 보여줌으로써 진단하기 어려운 문제나 오류를 식별하는 데 도움이 될 수 있다.

    Draw Debug는 게임 세계에서 모양, 선, 텍스트를 그리는 데 사용할 수 있는 몇 가지 기능을 제공한다. 이러한 모양은 플레이어 캐릭터, 적, 발사체와 같은 다른 게임 객체를 표현하는 데 사용될 수 있으며, 선은 이동 경로를 보여주거나 충돌을 추적하는 데 사용될 수 있다.

    예를 들어, 개발자가 물리적 충돌 문제를 디버깅하고자 할 경우, 그리기 디버그를 사용하여 관련된 객체의 충돌 모양을 시각화할 수 있다. 이렇게 하면 모양 또는 위치와 관련된 문제를 식별하고 문제를 디버깅하는 데 도움이 된다.

    Draw Debug 기능은 언리얼 편집기에서 사용하거나 사용하지 않도록 설정할 수 있으며, 다양한 모양과 선에 대해 다양한 색상과 스타일을 표시하도록 사용자 지정할 수 있습니다. 개발자는 또한 디버그 모양과 라인이 표시되는 기간을 제어할 수 있으며, 문서화 목적으로 스크린샷이나 비디오를 캡처하는 데 사용할 수 있다.

    전반적으로 Draw Debug는 언리얼 엔진에서 게임 로직과 동작을 디버깅하는 강력한 도구이며, 개발 중 문제를 진단하는 데 많은 시간과 노력을 절약할 수 있다.

     


     

    Global.h에 "DrawDebugHelpers.h"추가

     

    Global.h

    더보기
    #pragma once
    
    #include "DrawDebugHelpers.h"
    
    #include "Kismet/KismetSystemLibrary.h"
    
    #include "Utilities/CHelpers.h"
    #include "Utilities/CLog.h"
    • #include "DrawDebugHelpers.h" 추가

     

     


     

    C02_DrawDebug & BP_C02_DrawDebug 생성

     

    C02_DrawDebug.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "C02_DrawDebug.generated.h"
    
    UCLASS()
    class U2212_03_API AC02_DrawDebug : public AActor
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditAnywhere, Category = "Settings")
    		FVector InitLocation[5]; //시작위치 5곳 생성
    
    	UPROPERTY(EditAnywhere, Category = "Settings")
    		FBox Box; //박스 생성
    
    private:
    	UPROPERTY(VisibleAnywhere)
    		class UPointLightComponent* PointLight; //PointLight 생성 
    
    public:	
    	AC02_DrawDebug();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:	
    	virtual void Tick(float DeltaTime) override;
    
    private:
    	float EaseOutBounce(float x);
    
    private:
    	FVector Location[5]; //위치 5곳 생성
    };

     

     

    C02_DrawDebug.cpp

    더보기
    #include "02_Profiler/C02_DrawDebug.h"
    #include "Global.h"
    #include "Components/PointLightComponent.h"
    
    AC02_DrawDebug::AC02_DrawDebug()
    {
    	PrimaryActorTick.bCanEverTick = true;
    
    	CHelpers::CreateComponent <UPointLightComponent>(this, &PointLight, "PointLight");
    
    	InitLocation[0] = FVector(0, 0, 0);
    	InitLocation[1] = FVector(0, 1000, 0);
    	InitLocation[2] = FVector(0, 500, 0);
    	InitLocation[3] = FVector(0, 1500, 0);
    	InitLocation[4] = FVector(500, 1000, 0);
    
    	//Box의 중앙점을 (0,0,0)으로 잡음. Min은 앞쪽 좌하단, Max는 뒷쪽 우상단
    	Box = FBox(FVector(-50, -100, -50), FVector(50, 100, 50));
    }
    
    void AC02_DrawDebug::BeginPlay()
    {
    	Super::BeginPlay();
    }
    
    void AC02_DrawDebug::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	//내 위치 구하기
    	for (int32 i = 0; i < 5; i++)
    		Location[i] = InitLocation[i] + GetActorLocation();
    
    	//박스, 사각형 점 빌보드로 그려줌, 구, 2D 원, (2번에서 3번까지 길이의)선
    	DrawDebugSolidBox(GetWorld(), Location[0] + Box.GetCenter(), Box.GetExtent(), FColor::Red);
    	DrawDebugPoint(GetWorld(), Location[1], 100, FColor::Green);
    	DrawDebugSphere(GetWorld(), Location[2], 100, 30, FColor::Blue);
    	DrawDebugCircle(GetWorld(), Location[3], 100, 50, FColor::Magenta);
    	DrawDebugLine(GetWorld(), Location[2], Location[3], FColor::Yellow, false, -1, 0, 10); //bPersistentLines(false면 1frame, true면 duration), LifeTime, DepthPriority, Thickness
    
    	FVector location = Location[2];
    	location.X += 10;
    	location.Y += 10;
    	//location.Z += FMath::Sin(GetWorld()->GetTimeSeconds() * 5.0f) * 400.0f;
    	location.Z += EaseOutBounce(FMath::Sin(GetWorld()->GetTimeSeconds() * 2.5f)) * 200.0f;
    
    	DrawDebugCapsule(GetWorld(), location, 200, 50, FQuat::Identity, FColor::White);
    	DrawDebugDirectionalArrow(GetWorld(), Location[3], location, 400, FColor::Black, false, -1, 0, 20);
    
    	
    	bool b = FMath::Sign(FMath::Cos(GetWorld()->GetTimeSeconds() * 5.0f)) >= 0;
    	PointLight->SetVisibility(b); //PointLight가 SetVisibility로 깜박거리게 만들어준다.
    }
    
    //EaseOutBounce 함수. Easing함수 중 하나이다.
    float AC02_DrawDebug::EaseOutBounce(float x)
    {
    	const float n1 = 7.5625f;
    	const float d1 = 2.75f;
    
    	if (x < 1.0f / d1)
    	{
    		return n1 * x * x;
    	}
    	else if (x < 2.0f / d1)
    	{
    		return n1 * (x -= 1.5f / d1) * x + 0.75f;
    	}
    	else if (x < 2.5f / d1)
    	{
    		return n1 * (x -= 2.25f / d1) * x + 0.9375f;
    	}
    	else
    	{
    		return n1 * (x -= 2.625f / d1) * x + 0.984375f;
    	}
    }

     

    DrawDebug - SolidBox, Sphere, Circle, Line, Capsule, DirectionalArrow

    더보기
    void DrawDebugSolidBox(const UWorld* InWorld, FVector const& Center, FVector const& Extent, FColor const& Color, bool bPersistent, float LifeTime, uint8 DepthPriority)
    
    void DrawDebugPoint(const UWorld* InWorld, FVector const& Position, float Size, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority)
    
    void DrawDebugSphere(const UWorld* InWorld, FVector const& Center, float Radius, int32 Segments, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority, float Thickness)
    
    void DrawDebugCircle(const UWorld* InWorld, FVector Center, float Radius, int32 Segments, const FColor& Color, bool PersistentLines, float LifeTime, uint8 DepthPriority, float Thickness, FVector YAxis, FVector ZAxis, bool bDrawAxis)
    
    void DrawDebugLine(const UWorld* InWorld, FVector const& LineStart, FVector const& LineEnd, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority, float Thickness)
    
    
    void DrawDebugCapsule(const UWorld* InWorld, FVector const& Center, float HalfHeight, float Radius, const FQuat& Rotation, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority, float Thickness)
    
    void DrawDebugDirectionalArrow(const UWorld* InWorld, FVector const& LineStart, FVector const& LineEnd, float ArrowSize, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority, float Thickness)

     

     

     


     

    실행화면

     

    • 왼쪽에 PointLight가 깜박거린다.