[Unreal C++] 데이터 테이블 만들고, 사용하기 (CSV 파일)
참고 자료
'이득우의 언리얼 C++ 게임 개발의 정석' Chapter 11
&
데이터 테이블을 사용하는 이유
게임 데이터를 파일로 따로 관리하면 체계적으로 관리할 수 있고, 더 편하게 사용할 수 있다.
나는 엑셀이 없어서 구글 스프레드시트를 사용했다.
CSV 파일 만들기
엑셀 파일 형식은 사용할 수 없고, CSV 파일 형식으로 변환해야 사용할 수 있다.
CSV 파일로 변환해주자.
엑셀 파일의 1행을 비워놓아서, CSV 파일의 첫번째 줄에 의미 없는 (,,,,,)가 생겼다.
언리얼에서 오류가 날 수 있으니 지워주자.
데이터 테이블 구조체 만들기
각 열의 이름과 유형이 동일한 구조체를 선언해야 한다.
구조체를 생성할 때, USTRUCT, GENERATED_BODY() 매크로를 사용해줘야 에디터 인터페이스에서 볼 수 있다.
CSV 파일에서 1열에 있는 데이터는 언리얼 엔진에서 자동으로 키 값으로 사용된다.
위의 예제에서는 Name이 키 값으로 사용된다.
데이터를 담을 구조체를 만든다.
구조체의 선언 위치는 관리하기 쉽게, CustomDataTables라는 더미 액터를 만들어서 선언해주었다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Engine/DataTable.h" // 헤더 추가.
#include "CustomDataTables.generated.h"
USTRUCT(BlueprintType)
struct FABCharacterData : public FTableRowBase
{
GENERATED_BODY()
public:
FABCharacterData() : Level(1), MaxHP(100.0f), Attack(10.0f), DropExp(10), NextExp(30) {}
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
int32 Level;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
float MaxHP;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
float Attack;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
int32 DropExp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
int32 NextExp;
};
UCLASS()
class ARENABATTLE_API ACustomDataTables : public AActor
{
GENERATED_BODY()
};
CSV 파일 임포트하기
CSV 파일을 임포트한다.
이전에 만들었던 구조체로 연결을 해주고, 적용을 누른다.
데이터 테이블 로드하기
캐릭터 스텟 데이터는 변하지 않는 데이터이므로 보통 게임 앱이 초기화할 때 불러들인다.
게임 앱을 관리하기 위한 용도로 만들어진 게임 인스턴스를 사용해볼 것이다.
GameInstance를 부모클래스로 상속받아서 클래스를 만들고, 프로젝트 세팅에서 설정해준다.
헤더 파일
1. 데이터테이블 변수를 하나 만든다.
2. Getter 함수를 만들었다.
#pragma once
#include "ArenaBattle.h"
#include "Engine/GameInstance.h"
#include "ABGameInstance.generated.h"
struct FABCharacterData;
class UDataTable;
UCLASS()
class ARENABATTLE_API UABGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UABGameInstance();
FABCharacterData* GetABCharacterData(int32 Level);
private:
UPROPERTY()
UDataTable* ABCharacterTable;
};
CPP 파일
1. 생성자에서 데이터 테이블 리소스를 로드한다.
2. 해당 Level의 데이터를 반환한다.
#include "ABGameInstance.h"
#include "CustomDataTables.h"
UABGameInstance::UABGameInstance()
{
FString CharacterDataPath = TEXT("DataTable'/Game/Book/GameData/ABCharacterData.ABCharacterData'");
static ConstructorHelpers::FObjectFinder<UDataTable> DT_ABCHARACTER(*CharacterDataPath);
if (DT_ABCHARACTER.Succeeded())
{
ABCharacterTable = DT_ABCHARACTER.Object;
}
}
FABCharacterData* UABGameInstance::GetABCharacterData(int32 Level)
{
return ABCharacterTable->FindRow<FABCharacterData>(*FString::FromInt(Level), TEXT(""));
}
데이터 테이블 사용하기
GameInstance에 구현을 해놨으니까 가져다 쓰면 된다.
void AABCharacter::SetNewLevel(int32 NewLevel)
{
UABGameInstance* ABGameInstance = Cast<UABGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
if (nullptr == ABGameInstance) return;
CurrentStatData = ABGameInstance->GetABCharacterData(NewLevel);
if (CurrentStatData)
{
Level = NewLevel;
CurrentHP = CurrentStatData->MaxHP;
}
else
{
// 데이터 테이블에 없는 레벨일 때
UE_LOG(LogClass, Warning, TEXT("Level %d data doesn't exist."), NewLevel);
}
}