[ProjectXZ] 모듈러 캐릭터 개발일지 1. 데이터 기반으로 게임 시스템 구축하기

KWONYEONGMIN·2024년 10월 7일

언리얼

목록 보기
2/15
post-thumbnail

데이터 테이블 정의

  1. 제작한 테이블의 데이터를 담는 데이터 테이블 클래스 정의
  • FTableRowBase을 상속받은 클래스를 정의한다.

FTableRowBase

  • 데이터 테이블의 행(row)에 해당하는 구조체를 정의할 수 있으며, 테이블의 각 열(column)에 해당하는 데이터를 적절한 데이터 타입으로 저장할 수 있습니다.
  • 테이블의 Column 값에 알맞은 데이터 타입으로 멤버 변수를 정의해야 합니다.
  • BlueprintReadWrite UPROPERTY의 값으로 넣어줘야 합니다. => (그래야 파생한 블루 프린트 클래스에서 데이터를 확인할 수 있음)

USTRUCT(BlueprintType)
struct PROJECTXZ_API FItemTable_Module : public FTableRowBase
{
	GENERATED_BODY()
	public:
		FItemTable_Module() { }
		FItemTable_Module(int32 _ID, int32 _CATEGORY_ID, FString _ASSETNAME, FString _ASSETPATH, FString _IMAGEPATH)
			: ID(_ID), CATEGORY_ID(_CATEGORY_ID), ASSETNAME(_ASSETNAME), ASSETPATH(_ASSETPATH), IMAGEPATH(_IMAGEPATH)
		{
		}
		
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Module)
	int32 ID;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Module)
	int32 CATEGORY_ID;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Module)
	FString	ASSETNAME;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Module)
	FString	ASSETPATH;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Module)
	FString	IMAGEPATH;

};
  1. 해당하는 csv 테이블을 임포트 한다.

  2. 정의한 데이터 테이블 클래스를 블루 프린트 클래스로 생성한다.

  3. 임포트 한 csv 테이블을 블루 프린트에서 읽는다.
    - Reimport 버튼을 클릭
    - 데이터 값이 잘 들어간 걸 확인할 수 있다 !!


데이터 매니저 활용

저는 프로젝트에서 사용할 DataManager 클래스를 생성하여, FName 데이터 타입인 RowName 을 인자로 가지는 함수를 만들어, 해당하는 열을 리턴하도록 하는 유틸리티 기능을 구현하였습니다.

  1. DataManger는 UGameInstanceSubsystem 상속받은 클래스로 구현하여, 어디서나 접근 가능하도록 구현하였다.

UGameInstanceSubsystem 클래스

  • UGameInstanceSubsystem은 게임 인스턴스와 함께 생성되고, 게임 전체에서 접근할 수 있는 전역적인 객체입니다.
  • 특정 레벨에 한정되지 않고 프로젝트 내 어디서나 동일한 인스턴스에 접근 가능하여, 레벨 간의 전환이 이루어져도 데이터 테이블을 계속해서 활용할 수 있어, 데이터 관리에 매우 적합합니다.
  • DataManager는 시스템 전반에서 자주 사용되는 데이터 관리 기능을 포함하고 있으므로, 이를 GameInstanceSubsystem으로 구현하는 것이 적합하다고 판단하였습니다!
  1. 데이터 테이블에서 RowName에 해당하는 데이터를 검색하고 리턴하는 역할을 하는 함수를 구현한다.
  • FindRow 함수를 사용하여 데이터 테이블에서 특정 행을 찾고, 해당 행을 반환
FItemTable_Module* UXZDataManager::TryGetModuleAsset(FName RowName) const
{
    if ( !ModuleAssetTable )
    {
        UE_LOG(LogTemp, Warning, TEXT("Item ModuleAsset Table does not exist."));
        return nullptr;
    }

    FItemTable_Module* ModuleAssetTableRow = ModuleAssetTable->FindRow<FItemTable_Module>(RowName, TEXT("Item ModuleAssetTable Lookup"));

    if ( ModuleAssetTableRow )
    {
        UE_LOG(LogTemp, Warning, TEXT("Found Item ModuleAssetTable for RowName: %s"), *RowName.ToString());
        return ModuleAssetTableRow;
    }

    UE_LOG(LogTemp, Warning, TEXT("Could not find Item ModuleAssetTable for RowName: %s"), *RowName.ToString());
    return nullptr;
}
  1. 데이터 매니저를 사용해서 DataTable을 가지고 온다.

    LoadObject 함수를 통해 동적으로 애셋을 로드할 수 있습니다.

  if ( const UXZDataManager* DataManager = UGameInstance::GetSubsystem<UXZDataManager>(GetWorld()->GetGameInstance()) )
  {
  ...
      if ( FItemTable_Module* ModuleAsset = DataManager->TryGetModuleAsset(ModuleIDName) )
      {
        ...
          UXZAssetManager& AssetManager = UXZAssetManager::GetXZAssetManager();
          FSoftObjectPath AssetPath = ModuleAsset->ASSETPATH;	// 데이터 테이블의 AssetPath
         
         // Asset Manager, RequestAsyncLoad 함수를 사용하여 비동기 로드 구현
         AssetManager.GetStreamableManager().RequestAsyncLoad(AssetPath, FStreamableDelegate::CreateLambda([this, SkeletalMeshComponent, AssetPath]()
          {
          // 애셋 로드가 끝난 후 실행될 코드
              if (USkeletalMesh* SkeletalMesh = Cast<USkeletalMesh>(AssetPath.TryLoad()))
              {
                  SkeletalMeshComponent->SetSkeletalMesh(SkeletalMesh);
		...
              }
          }));
      }
  }
profile
Hello World

0개의 댓글