Make Unreal REAL.
article thumbnail
이득우의 언리얼 C++ 게임 개발의 정석

 

우선 ABCharacterSetting 클래스는 ArenaBattleSetting 모듈에 생성된 언리얼 오브젝트이므로 CoreMiminal.h를 ArenaBattleSetting.h로 변경한다.

 

 

언리얼 엔진은 언리얼 오브젝트의 기본값을 유연하게 관리하도록 외부 INI 파일에서 기본 속성 값을 가져오는 기능을 제공한다.

 

INI 파일에서 기본값을 불러들이기 위해서는 UCLASS 매크로에 config 키워드와 설정 이름을 추가해야 한다.

  • 프로젝트의 Config/Default{설정 이름}.ini 파일을 참조한다.

 

애셋은 가상 경로만 알면 프로그램에서 로딩할 수 있다.

  • INI에서 불러들인 가상 경로는 FSoftObjectPath라는 클래스로 저장된다.
  • FSoftObjectPath.ToString() 함수로 FString 타입으로 변환할 수 있다.

 

INI 파일에는 여러 개의 가상 경로가 작성되어 있으므로 TArray<FSoftObjectPath> 타입으로 지정해야 한다.

  • 속성에도 UPROPERTY 매크로와 config 키워드를 추가해야 한다.

 

이렇게 설정하면 언리얼 엔진은 언리얼 오브젝트를 초기화할 때 해당 속성의 값을 INI 파일에서 불러들인다.

 

 

INI 파일은 다음과 같은 형식이다.

  • 이때, 언리얼 오브젝트 변수의 이름과 INI에 설정된 변수의 이름이 같아야 한다.

 

 

일단 생성자의 내용은 비워둔다.

 

 

ArenaBattle 모듈의 ABCharacter에서 ArenaBattleSetting 모듈의 ABCharacterSetting을 참고해 캐릭터 에셋 목록을 얻어올 것이다.

 

ArenaBattle의 빌드 설정에 ArenaBattleSetting 모듈을 추가한다.

  • PublicDependencyModuleNames에 추가되면 Public, Private 폴더 모두에서 사용할 수 있다.
  • PrivateDependencyModuleNames에 추가되면 Private 폴더에서만 사용할 수 있다.

 

 

ArenaBattleSetting 모듈을 추가했으므로, 이제 ABCharacter 클래스에서 ABCharacterSetting 클래스를 참조할 수 있다.

 

 

언리얼 엔진이 초기화되면 구동에 필요한 모듈이 순차적으로 로딩된다.

  • 각 모듈은 자신에게 속한 모든 언리얼 오브젝트의 기본값을 지정해 클래스 기본 객체(CDO, Class Default Object)를 생성한다.
  • 따라서 엔진이 초기화되면 모든 언리얼 오브젝트의 클래스 기본 객체가 메모리에 올라간 상태가 된다.

 

CDO에는 각 언리얼 오브젝트의 기본값이 지정되어 있으므로, GetDefault() 함수를 이용해 CDO를 가져오면 클래스의 기본값을 가져올 수 있다.

 

현재 ArenaBattleSetting 모듈이 ArenaBattle 모듈보다 먼저 로딩되도록 설정되어 있으므로, ArenaBattle의 ABCharacter에서 GetDefault() 함수를 통해 ArenaBattleSetting의 ABCharacterSetting CDO에 있는 CharacterAssets 값을 가져올 수 있다.

  • 기본값은 변경할 수 없으므로 GetDefault의 반환값은 const로 받아야 한다.

 

 

컴파일하면 ABCharacter의 생성자에서 에셋 목록을 출력하는 것을 확인할 수 있다.

 

 

기존에는 생성자에서 미리 캐릭터 에셋을 지정했지만, 게임 진행 중에도 비동기 방식으로 에셋을 로딩할 수 있다.

 

"Engine/StreamableManager.h" 헤더를 포함하면 FStreamableManager라는 클래스를 통해 런타임 중 비동기 방식으로 에셋을 로딩할 수 있다.

  • "Engine/AssetManager.h" 헤더를 포함하고 UAssetManager::GetStreamableManager() 함수로 바로 가져와도 된다.

 

ABGameInstance 클래스에 헤더를 포함하고 FStreamableManager 타입의 매니저 변수를 선언한다.

  • 이 매니저 클래스는 프로젝트에서 하나만 활성화하는 것이 좋기 때문에 싱글톤처럼 동작하는 ABGameInstance 클래스에 멤버 변수로 선언한다.

 

 

참고로, Project Settings > General Settings > Default Classes에서 싱글톤으로 관리할 클래스, 에셋 매니저 클래스 등을 지정할 수 있다.

 

 

ABCharacter 클래스에 FStreamableDelegate 타입의 델리게이트에 등록할 함수와 비동기 실행을 관리할 핸들을 선언한다.

  • 핸들은 여러 개의 포인터가 가리킬 수 있는 TSharedPtr<FStreamableHandle> 타입의 스마트 포인터이다.

 

 

ABGameInstance에서 StreamableManager를 가져오기 위해 헤더를 포함한다.

 

 

BeginPlay()에서 ArenaBattleSetting 모듈의 UABCharacterSetting 오브젝트에 있는 CharacterAssets 에셋 목록에 접근해 랜덤으로 하나의 가상 경로를 가져오도록 한다.

  • GetDefault() 함수로 UABCharacterSetting 클래스의 CDO를 가져온다.
  • TArray::Num() 함수를 통해 배열의 길이를 가져올 수 있고 FMath::RandRange(InMin, InMax) 함수를 통해 범위 사이의 랜덤 숫자를 뽑을 수 있다.
  • ABGameInstance의 StreamableManager 멤버를 가져와 비동기 로딩을 실행한다.

 

BeginPlay()에서 비동기 로딩을 수행하지 않고 생성자에서 랜덤 가상 경로를 지정하고 에셋을 가져와도 된다.

  • 단, ConstructorHelpers::FObjectFinder 타입의 변수의 static을 지워주지 않으면 모든 캐릭터가 같은 에셋을 쓰게 된다.
  • 언리얼 에디터에서는 이미 월드에 배치된 액터의 기본값 변경이 적용되지 않는 경우가 많으므로, 계속 다시 플레이를 해도 같은 모습을 하고 있을 가능성이 크다.

 

FStreamableManager::RequestAsyncLoad() 함수로 비동기 에셋 로딩을 수행할 수 있다.

  • FStreamableDelegate 타입의 델리게이트를 넘겨주면 에셋 로딩이 끝난 후 등록된 함수를 호출해준다.
    이 델리게이트는 하나의 함수만 등록할 수 있는 유니캐스트 델리게이트(Unicast Delegate)이다.
  • FStreamableDelegate 타입의 멤버를 선언해 넘겨줘도 되지만, FStreamablaDelegate::CreateUObject() 함수로 함수가 등록된 델리게이트를 즉석에서 만들어 전달할 수도 있다.
  • TSharedPtr<FStreamableHandle> 타입의 스마트 포인터를 관리 핸들로서 반환한다.

 

 

비동기 에셋 로딩이 끝나면 발동하는 델리게이트에 등록할 함수이다.

 

FStreamableHandle::GetLoadedAsset() 함수를 이용해 로딩이 완료된 에셋을 가져올 수 있다.

  • FObjectFinder처럼 .Object() 함수를 사용하지 않고 Cast() 함수로 바로 캐스팅해 사용한다.

 

사용한 핸들 스마트 포인터는 TSharedPtr::Reset() 함수를 실행시켜 메모리를 해제한다.

 

 

캐릭터 에셋 목록을 관리하는 모듈을 제작하고 INI 파일과 연동해 랜덤으로 캐릭터 에셋을 설정하는 데 성공했다.

 

profile

Make Unreal REAL.

@diesuki4

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그