디버깅 출력

Taegang Yun·2024년 6월 8일
0

Unreal

목록 보기
3/11

디버깅을 위한 출력

보통 Output Log 창에 로그를 보고 경고나 에러를 확인함.
Toolbar > Window > Output Log를 클릭하면 하단에 열림.

UE_LOG(로그카테고리, 로그수준, 형식문자열, 인자) 함수

  • 로그카테고리: 로그의 분류를 위해 카테고리 지정 가능. Output Log 창에서 필터링 가능.
    Filters > Categories > Show all의 체크 해제 후 LogTemp만 체크.
    혹은 검색창에 LogTemp 검색
  • 로그수준: Output Log 창에서 로그 수준에 따라 색상이 달라짐.
    Log는 흰색, Warning은 노란색, Error는 빨간색.
  • 형식문자열: 출력할 문자열. C언어의 printf() 함수의 인자 중 형식 문자열과 유사함.
  • 인자: 형식문자열에 출력할 값.

USGameInstance 클래스 실습

  • USGameInstance 클래스 관련 실습 준비
    GameInstance에는 중요한 함수가 몇 개 있음.
    대표적으로 게임이 시작될 때 호출되는 Init() 함수와 종료될 때 호출되는 ShutDown() 함수.
    해당 함수를 오버라이드해서 언제 호출되는지 알아보고자 함.
    언리얼 엔진 로직의 함수를 오버라이드 할 때는 부모 클래스로 가서 해당 함수 선언 확인.
    접근지정자와 반환자료형, 매개변수목록 등을 그대로 복사해오면 됨.
// SGameInstance.h

...
class STUDYPROJECT_API USGameInstance : public UGameInstance
{
    ...

public:
    ...

    virtual void Init() override;

    virtual void Shutdown() override;
    
};
// SGameInstance.cpp


...

void USGameInstance::Init()
{
    Super::Init(); // 엔진 업데이트 루틴을 지키기 위해서, 언리얼 엔지니어가 작성한 코드가 먼저 실행되게끔 하기 위함.

    UE_LOG(LogTemp, Log, TEXT("USGameInstance::Init() has been called."));
}

void USGameInstance::Shutdown()
{
    

    UE_LOG(LogTemp, Log, TEXT("USGameInstance::Shutdown() has been called."));
    
    Super::Shutdown();
}
  • Super : 바로 부모 클래스의 함수 실행

UKismetSystemLibrary::PrintString() 함수

디버깅 용도로 개발시에 자주 사용하는 또 다른 함수는 UKismetSystemLibrary::PrintString()
다만 구현한 로직을 릴리즈 버전으로 배포할 때는 주석 처리를 걸어둬야함.

// SGameInstance.cpp


...
#include "Kismet/KismetSystemLibrary.h"

...

void USGameInstance::Init()
{
	Super::Init();

	UE_LOG(LogTemp, Log, TEXT("Init() has been called."));

	UKismetSystemLibrary::PrintString(GetWorld(), TEXT("Init() has been called."));
		// UKismetSystemLibrary::PrintString() 함수는 인자로 "WorldContextObject" 라는걸 받음.
		// Context란, ~될만한거 라고 생각하면 좋음. 여기서는 "월드 개체를 만들만한 거"라고 해석.
		// 따라서 GetWorld()를 통해서 진짜 World 개체를 넘겨줘도 되지만
		// this(USGameInstance 개체)를 전달해서 this가 속한 월드 개체를 구하게끔 해도된다는 뜻.
}

...

check(조건식), ensure(조건식) 구문

함수의 인자로 전달한 조건식이 거짓일 경우 check() 함수는 크래시를 발생시킴.
ex. check(nullptr != GameInstance)
그냥 크래시만 내기보다, 보통은 checkf() 함수를 활용해서 추가적인 디버깅 정보를 출력함.
ex. checkf(nullptr != GameInstance, TEXT(”Invalid GameInstance.”))
그러나, 실행 중에 크래시를 발생시켜서 재빌드 시간이 부담이라면 ensure() 함수로 에러 메세지를 띄움.
ex. ensure(nullptr != GameInstance)
마찬가지로 그냥 에러 메세지를 띄우기 보다 ensureMsgf() 함수로 추가적인 디버깅 정보를 출력.
ex. ensureMsgf(nullptr != GameInstance, TEXT(”Invalid GameInstance.”))

// SGameInstance.cpp


...

void USGameInstance::Init()
{
	...

	UWorld* World = GetWorld();
	if (IsValid(World) == true)
	{
		// 이런 식으로도 할 순 있지만, 만에하나 World 개체가 유효하지 않다면?
		// 아무런 로직이 돌지 않으므로 팀원은 잘못된건지 알 수 없음.
		// World 개체가 없다는건 큰 문제이므로 이럴 때 checkf() 매크로 함수나 ensureMsgf() 매크로 함수를 활용.
		UKismetSystemLibrary::PrintString(World, TEXT("Init() has been called."));
	}

	checkf(IsValid(World) == true, TEXT("Invalid World."));
		// checkf() 매크로 함수를 잘 활용하면 if() 구문도 줄어서 더 깔끔한 코드 작성도 가능.

	UKismetSystemLibrary::PrintString(World, TEXT("Init() has been called."));	
}

...

이게 없으면 말이 안돼!! 하는건 check로 하는게 확실. if문은 그냥 넘어가니까.

  • IsValid() 함수
    런타임 중에 개체의 포인터가 유효한지 검사 할때 쓰는 함수.
    널포인터인지 아닌지만 검사하면 Pending Kill이나 GC의 대상인 경우를 확인 할 수 없음.
    IsValid() 함수를 활용하면 위 세 가지를 모두 체크해줌. 문제없다면 true 반환.

  • 예외처리와 checkf() 매크로 함수
    “이건 false 일 수도 있음. 이때는 그냥 처리 안하면 됨.” → 예외처리
    “이건 false 일 수가 없음. 이 로직을 실행하려는 사람에게 알려야함.” → checkf() 매크로 함수

profile
언젠간 전문가가 되겠지

0개의 댓글