본문 바로가기

언리얼5/공부기록

UE 게임 데이터 관리

엑셀 데이터 임포트

DataAsset과 유사하게 FTableRowBase를 상속받은 구조체를 선언

엑셀의 Name 칼럼을 제외한 칼럼과 동일하게 UPROPERTY 속성을 선언

엑셀 데이터를 csv로 익스포트한 후 언리얼 엔진에 임포트

USTRUCT(BlueprintType)
struct FABCharacterStat : public FTableRowBase
{
	GENERATED_BODY()
}

 

스탯 합산 기능 

FABCharacterStat operator+(const FABCharacterStat& Other) const
	{
		const float* const ThisPtr = reinterpret_cast<const float* const>(this);
		const float* const OtherPtr = reinterpret_cast<const float* const>(&Other);

		FABCharacterStat Result;
		float* ResultPtr = reinterpret_cast<float*>(&Result);
		int32 StatNum = sizeof(FABCharacterStat) / sizeof(float);
		for (int32 i = 0; i < StatNum; i++)
		{
			ResultPtr[i] = ThisPtr[i] + OtherPtr[i];
		}

		return Result;
	}

 

코드 해석
1. 함수 연산자 오버로딩 + 사용

2. 2개의 동일한 스탯 구조체를 가져온다 (멤버데이터는 반드시 모두 실수형이여야만 한다.)

3. reinterpret_cast 로 데이터들을 레퍼런스를 참조한다. (원본은 수정되면 안되니 const를 지정한다)
4. 선언된 맴버변수 갯수  = 구조체 전체 사이즈 / 실수 사이즈

5. 선언된 맴버변수 갯수로 순회하면 동일한 데이터 값들이 순차적으로 연산이 가능하다.

 

모든것이 실수형 데이터로 되어있다고 가정이 되면

이 전체 구조체의 데이터는 실수형의 집합으로 구성된다

 

데이터 테이블 객체 생성

마우스 우측클릭 -> 기타 -> 데이터 테이블 생성 -> 내가 만든 클래스를 부모 클래스로 지정


언리얼 싱글톤 클래스

  • 게임 인스턴스
  • 애셋 매니저
  • 게임 플레이 관련 액터(게임모드 게임 스테이트)
  • 프로젝트에 싱글톤으로 등록한 언리얼 오브젝트

UObject클래스 기반 싱글톤 클래스 생성방법

UObject클래스 상속받는 GameSingleton 클래스 생성

1. 엔진 -> General Setting -> Game Singleton Class 에서 방금 만든 싱글톤 클래스 선택

2. 프로젝트를 재시작해야 수정된 사항 반영됨

3. 멤버변수 가변배열로 스탯 구조체 변수 선언

4. 싱글톤 instance Get 함수 구현

UABGameSingleton& UABGameSingleton::Get()
{
	UABGameSingleton* Singleton = CastChecked< UABGameSingleton>(GEngine->GameSingleton);
	if (Singleton)
	{
		return *Singleton;
	}

	UE_LOG(LogABGameSingleton, Error, TEXT("Invalid Game Singleton"));
	return *NewObject<UABGameSingleton>();
}

프로젝트 셋팅에서 싱글톤 클래스를 지정받았기에 GEngine->GameSingleton은 우리가만든 싱글톤 클래스를 반환한다

 


테이블 데이터를 멤버 가변 배열로 파싱

UABGameSingleton::UABGameSingleton()
{
	static ConstructorHelpers::FObjectFinder<UDataTable> DataTableRef(TEXT("/Script/Engine.DataTable'/Game/ArenaBattle/GameData/ABCharacterStatTable.ABCharacterStatTable'"));
	if (nullptr != DataTableRef.Object)
	{
		const UDataTable* DataTable = DataTableRef.Object;
		check(DataTable->GetRowMap().Num() > 0);

		TArray<uint8*> ValueArray;
		DataTable->GetRowMap().GenerateValueArray(ValueArray);
		Algo::Transform(ValueArray, CharacterStatTable,
			[](uint8* Value)
			{
				return *reinterpret_cast<FABCharacterStat*>(Value);
			}
		);
	}

	CharacterMaxLevel = CharacterStatTable.Num();
	ensure(CharacterMaxLevel > 0);
}

 

코드 해석

1. 우리가 생성한 테이블 데이터의 레퍼런스를 지역변수로 get (가져온 데이터의 갯수가 0이상인지도 확인해야함)

2. 테이블 데이터는 맵 타입을 반환하는데 이것을 가변배열로 캐싱한다.

3. Algo::Transform 함수를 활용하여 싱글톤 멤버변수로 미리 선언했던 배열에 람다식을 사용해서 초기화.
 - 매개변수(이터레이팅할 배열,Set할 대상)
 - ValueArray는 람다식으로 요소값의 순차적인 접근이 Value로 가능하지만 Set할 대상은 순차적인 요소 접근은 불가능한것으로 보인다.

4. 정상적으로 배열이 정의되었는지 Num을 체크하여 확인

 


캐릭터 스탯 성장 구조
ActorComponent CharacterComponent

플레이어 스탯은 베이스 스탯과 모디파이어 스탯의 합으로 생성된다.

  • 베이스 스탯 : 레벨 데이터 기준으로 성장하는 테이블 데이터 스탯을 의미한다.
  • 모디파이어 스탯 : 무기 ,버프효과로 추가 또는 차감되는 데이터 스탯을 의미한다.

두 스탯은 이전 구조체의 오퍼레이터로 합이 쉽게 가능해진다.

 

베이스 스탯은 플레이어의 현제 레벨을 기준으로 싱글톤에서 스탯값을 탐색해서 가져온다.

 


언리얼 지연 생성함수 (lock같은거)

  • SpawnActorDeferred<class> 비긴 함수 호출의 지연시간을을 생성한다
  • FinishSpawning  생성한 객체지연을 닫으면 이후 비긴함수가 호출된다.

필요한경우 레벨이 증가된 이후 비긴함수에서 증가된 레벨을 기준으로 스탯을 초기화해야한다

하지만 SpawnActor로 캐릭터는 인스턴싱하면 구현한 게임 로직보다 비긴이 우선시 호출되어
증가된 레벨을 반영받지 못하는경우가 발생한다 이런경우를 위해 언리얼이 지원하는 SpawnActorDeferred로 지연하여 비긴이 나중에 호출되게 처리하는방법을 사용한다.