멈추지 않고 끈질기게

[Unreal] StaticConstructorHelpers 관련 이슈 본문

Unreal

[Unreal] StaticConstructorHelpers 관련 이슈

sam0308 2024. 7. 1. 17:08

※ 해당 포스팅은 개인의 공부 정리용 글입니다. 틀린 내용이 있다면 추후 수정될 수 있습니다.

※ 해당 포스팅은 Unreal 5.4.1 버전을 기준으로 작성되었습니다.

 

 

 

1. static 유무의 차이

 기본적으로 ConstructorHelpers의 FClassFinder 혹은 FObjectFinder 함수를 사용할 때는 static을 붙여서 호출해야 해당 에셋을 한번만 로드하고, 모든 인스턴스에서 공유하므로 메모리 성능면에서 좋다고 알고 있었습니다. 그래서 습관적으로 static을 붙여서 사용하고 있었는데, static을 붙이면 안되는 경우를 겪었습니다.

 

// Portraits
// Joy
for(int32 i = 1; i < 5; ++i)
{
	FString RefText = FString::Printf(TEXT("/Script/Engine.Texture2D'/Game/PKH/Portaraits/Artist/Artist_Joy%d.Artist_Joy%d'"), i, i);
	// static 사용
        static ConstructorHelpers::FObjectFinder<UTexture2D> Portrait_JoyRef(*RefText);
	if (Portrait_JoyRef.Object)
	{
		Portraits_Joy.Add(Portrait_JoyRef.Object);
	}
}

 

 생성자에서 상기 코드를 사용하여 비슷한 이름의 파일들을 반복문으로 로드하려 했으나, 결과물을 확인해보니 Portraits_Joy 배열에 i = 1일 때의 파일만 들어가 있는 이슈가 발생했습니다.

사진 1. 동일 파일만 들어가는 이슈

 

 상기 코드를 분석해본 결과, static이 범인이었습니다. Portrait_JoyRef라는 FObjectFinder를 static으로 선언하였기 때문에, 처음(i = 1)에 초기화되고 나면 해당 에셋으로 고정되어서 이후 반복문에서 아무리 호출해도 바뀌지 않는 것이었습니다. static을 제거하고 나서 제가 원하던 모습으로 1번부터 4번 파일까지 순서대로 배열에 등록된 모습을 확인할 수 있었습니다. static의 성질을 생각하면 어찌보면 당연한 내용인데, 앞으로는 습관을 조심하도록 해야겠습니다.

 

// Portraits
// Joy
for(int32 i = 1; i < 5; ++i)
{
	FString RefText = FString::Printf(TEXT("/Script/Engine.Texture2D'/Game/PKH/Portaraits/Artist/Artist_Joy%d.Artist_Joy%d'"), i, i);
	// static 제거
        ConstructorHelpers::FObjectFinder<UTexture2D> Portrait_JoyRef(*RefText);
	if (Portrait_JoyRef.Object)
	{
		Portraits_Joy.Add(Portrait_JoyRef.Object);
	}
}

사진 2. static 제거 후

 

 

2. 언리얼 엔진이 실행되지 않는 이슈

 이번에는 ConstructorHelpers 관련 좀 더 심각하고 황당한 이슈에 대해 소개하겠습니다. 팀 프로젝트를 진행하면서 시작 화면 및 튜토리얼을 관련 내용을 한 레벨에 합치는 작업을 하던 중, 비주얼 스튜디오에서 빌드 후 실행하자 언리얼 엔진이 75%에서 로딩이 멈추는 이슈가 발생하였습니다.

사진 3. 언리얼 엔진 무한 로딩

 

 심지어 uproject 파일로 실행해도 동일하게 발생했습니다. 원인을 도저히 찾지 못하다가 우선 깃에서 이전 커밋 기준으로 브랜치를 새로 파서 해당 파일로 덮어씌우는 방식으로 원복했습니다.

사진 4. 이전 커밋으로 브랜치 생성

 

 이후에 추가한 코드들을 주석처리하고 풀며 일일히 원인을 찾아본 결과, 생성자의 FClassFinder() 함수가 범인임을 찾을 수 있었습니다. 튜토리얼에 사용하는 WBP를 게임모드의 생성자에서 FClassFinder로 등록하는 코드를 주석처리하자 해당 이슈가 발생하지 않았습니다.

사진 5. FClassFinder 주석 처리

 

 다만 진짜 문제는 해당 이슈의 원인을 모르겠다는 점입니다. 저는 원래 UI도 항상 FClassFinder()를 통해 TSubclassOf<> 타입으로 등록한 뒤 CreateWidget()에서 해당 변수를 사용하였는데, 해당 이슈는 처음 겪어보았습니다. 그나마 의심가는 점이라면 해당 WBP는 관련 로직도 전부 블루프린트로 이루어져 있는데, 이러한 위젯을 cpp 파일의 생성자에서 등록하려 하면 이슈가 발생할 수 있다 정도로 보고 있습니다. 다만 저도 아주 간단한 WBP는 블루프린트만 사용하곤 했어서, 정확한 원인은 아닌 것 같습니다. 

 

 대신 이후에 팀원 분도 동일한 이슈를 겪으셨는데, 생성자에서 의심가는 부분을 제거함으로서 빠르게 해결할 수 있었습니다. 이후에도 동일한 이슈가 발생하면 우선 생성자를 의심해 보아야겠습니다.