Unreal

[Unreal C++] 데이터 테이블 만들고, 사용하기 (CSV 파일)

푸쿠이 2021. 5. 10. 13:07
참고 자료

'이득우의 언리얼 C++ 게임 개발의 정석' Chapter 11

&

wergia.tistory.com/154

 

데이터 테이블을 사용하는 이유

게임 데이터를 파일로 따로 관리하면 체계적으로 관리할 수 있고, 더 편하게 사용할 수 있다.

나는 엑셀이 없어서 구글 스프레드시트를 사용했다.

 

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);
	}
}