이전 글 보기
https://mountain-noroo.tistory.com/65
[언리얼] 학원 18일차: 액터 위 UI, 인벤토리(리스트)
이전 글 보기 https://mountain-noroo.tistory.com/64 [언리얼] 학원 17일차: 버튼, RenderTexture 이전 글 보기 https://mountain-noroo.tistory.com/63 [언리얼] 학원 16일차: UMG: 언리얼 UI 이전 글 보기 https://mountain-noroo.tisto
mountain-noroo.tistory.com
아이템 데이터 테이블
아이템을 추가할 때마다 데이터를 하나하나 세팅해 주는 것은 비효율적이기 때문에 아이템에 대한 데이터 테이블을 하나 만들어주었다.
UENUM(BlueprintType)
enum class EITEM_ID : uint8
{
CI_POTION,
CI_MEGAPORION,
EW_LONGSWORD,
EW_DAGGER,
EW_BOW,
EA_LEATHER_ARMOR,
EA_STEEL_ARMOR,
EA_PLATINUM_ARMOR
};
UENUM(BlueprintType)
enum class EITEM_TYPE : uint8
{
WEAPON,
ARMOR,
ACCESSORY,
CONSUMABLE,
END,
};
enum을 모아둔 헤더에
모든 아이템을 구분하기 위한 EITEM_ID와
언젠가 사용할 수 있도록 타입을 구분하는 EITEM_TYPE enum을 만들었다.
EITEM_TYPE의 END라는 타입은 타입의 개수를 나타내기 위해 만들었다.
현재 4개의 타입이 존재하기 때문에 순서대로 0, 1, 2, 3, 4이라는 값을 가지게 된다.
자연스럽게 4개의 타입이 있다는 정보값을 가지게 되는 것.
// 아이템 구조체
USTRUCT(Atomic, BlueprintType)
struct FGameItemInfo
: public FTableRowBase
{
GENERATED_BODY();
UPROPERTY(EditAnywhere, BlueprintReadWrite)
EITEM_ID ID;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
EITEM_TYPE TYPE;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Description;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString IconPath;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Att;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Def;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Heal_HP;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Heal_MP;
};
그리고 아이템 데이터 테이블을 만들기 위한 FGameItemInfo 구조체를 만들었다.
데이터 테이블을 만들기 위해서는 FTableRowBase를 상속해야 한다는 사실을 잊지 말자.
ID, Type, 설명, 아이콘 주소, 기타 아이템 능력치 수치값을 저장한다.
데이터 테이블을 만드는 방법은 예전 포스팅에서 볼 수 있다.
https://mountain-noroo.tistory.com/59
[언리얼] 학원 12일차: 데칼, 몬스터 개선(데이터 테이블)
이전 글 보기 https://mountain-noroo.tistory.com/58 [언리얼] 학원 11일차: 또 다른 싱글톤, 콜리전 트레이스 채널 이전 글 보기 https://mountain-noroo.tistory.com/57 [언리얼] 학원 9일차: 투사체 개선, 충돌체 이전
mountain-noroo.tistory.com
인벤토리 매니저 싱글톤
획득한 아이템을 관리하고 손쉽게 추가하기 위해 인벤토리 매니저 싱글턴 객체를 만들었다.
이번에는 GameInstance에 부착하여 게임 전체와 라이프 사이클을 함께하도록 할 것이다.
싱글톤을 만드는 방법에 대한 설명은 예전 포스팅에서 볼 수 있다.
https://mountain-noroo.tistory.com/56
[언리얼] 학원 8일차: SpawnActor, 싱글톤, 투사체
이전 기록 https://mountain-noroo.tistory.com/54 [언리얼] 학원 7일차: 애니메이션 노티파이와 파티클, 나이아가라 이전 기록 https://mountain-noroo.tistory.com/53 [언리얼] 학원 6일차: Data Asset과 Fire 액션 추가 이
mountain-noroo.tistory.com
https://mountain-noroo.tistory.com/58
[언리얼] 학원 11일차: 또 다른 싱글톤, 콜리전 트레이스 채널
이전 글 보기 https://mountain-noroo.tistory.com/57 [언리얼] 학원 9일차: 투사체 개선, 충돌체 이전 기록 https://mountain-noroo.tistory.com/56 [언리얼] 학원 8일차: SpawnActor, 싱글톤, 투사체 이전 기록 https://mountain-
mountain-noroo.tistory.com
UCLASS()
class UNREAL_3TH_API UInvenMgr : public UObject
{
GENERATED_BODY()
private:
static UWorld* m_World;
public:
static UInvenMgr* GetInst(UWorld* _World);
static UInvenMgr* GetInst(UGameInstance* _GameInst);
};
UCLASS()
class UNREAL_3TH_API UGameInstance_Base : public UGameInstance
{
GENERATED_BODY()
private:
UInvenMgr* m_InvenMgr;
public:
UGameInstance_Base();
~UGameInstance_Base();
friend class UInvenMgr;
};
GameInstance에도 포인터 객체로 선언하였다.
아래에 friend class라는 코드를 확인할 수 있다.
이는 friend class라고 선언한 클래스에서 이 클래스의 private, protect에 접근할 수 있게 해 준다는 것이다.
여기서 중요한 점은 UInvenMgr 클래스가 UGameInstance_Base 클래스의 private, protect 멤버에 접근할 수 있는 것이지 그 반대로 헷갈리면 안 된다.
비유하자면 UGameInstance_Base는 UInvenMgr를 친구라고 생각하지만 UInvenMgr는 보여주고 싶지 않을 수도 있단 뜻
UWorld* UInvenMgr::m_World = nullptr;
UInvenMgr* UInvenMgr::GetInst(UWorld* _World)
{
m_World = _World;
return GetInst(m_World->GetGameInstance());
}
UInvenMgr* UInvenMgr::GetInst(UGameInstance* _GameInst)
{
UGameInstance_Base* pGameInst = Cast<UGameInstance_Base>(_GameInst);
if (!IsValid(pGameInst->m_InvenMgr))
{
pGameInst->m_InvenMgr = NewObject<UInvenMgr>();
pGameInst->m_InvenMgr->AddToRoot();
}
return pGameInst->m_InvenMgr;
}
그래서 UInvenMgr 클래스 안이지만 UGameInstance_Base의 m_InvenMgr에 접근할 수 있는 것이다.
8일 차 포스팅에서 만들었던 싱글톤 기법과 거의 동일하니 설명은 해당 포스팅을 참고 바란다.
인벤토리 매니저 구현
본격적으로 인벤토리 매니저의 기능을 구현한다.
구현하는 기능은 아래와 같다.
- 데이터 테이블에서 아이템들에 대한 정보를 가져오는 기능
- 인벤토리에 아이템을 넣는 기능
- 인벤토리를 열면 아이템을 보여주는 기능
USTRUCT()
struct FItemStack
{
GENERATED_BODY();
FGameItemInfo* ItemInfo;
int32 Stack;
};
매니저 구현에 앞서
어떤 아이템이 몇 개 있는지까지 정보를 저장하기 위해 구조체를 하나 만들었다.
UCLASS()
class UNREAL_3TH_API UInvenMgr : public UObject
{
GENERATED_BODY()
private:
static UWorld* m_World;
private:
// 아이템 데이터 테이블
UDataTable* m_ItemTable;
// 아이템 정보
TMap<EITEM_ID, FGameItemInfo> m_mapItemInfo;
// 보유 아이템
TMap<EITEM_ID, FItemStack> m_BackPack[(int32)EITEM_TYPE::END];
public:
static UInvenMgr* GetInst(UWorld* _World);
static UInvenMgr* GetInst(UGameInstance* _GameInst);
// 테이블 정보를 변수에 TMap 변수에 저장하기 위함
void SetGameItemDataTable(UDataTable* _ItemDataTable);
// 아이템 획득 시 추가
void AddGameItem(EITEM_ID _ID);
// 인벤토리를 열 때
void OpenInventoryUI();
TMap <T1, T2>는 언리얼에서 사용하는 Map형 자료구조로
데이터 테이블의 정보를 ID에 매핑시켜 가져올 변수와
지금 인벤토리에 무슨 ID의 아이템이 몇 개 들어있는지 저장할 변수 배열을 선언하였다. 이 배열은 타입별로 나누어진다.
데이터 테이블에서 아이템들에 대한 정보를 가져오는 기능
UGameInstance_Base::UGameInstance_Base()
: m_InvenMgr(nullptr)
{
ConstructorHelpers::FObjectFinder<UDataTable> tablefinder(TEXT("/Script/Engine.DataTable'/Game/BlueprintClass/Item/DT_GameItem.DT_GameItem'"));
if (tablefinder.Succeeded())
{
UInvenMgr::GetInst(this)->SetGameItemDataTable(tablefinder.Object);
}
else
{
LOG(LogTemp, Error, TEXT("게임 아이템 데이터 테이블 못 찾음"));
}
}
아이템 데이터 테이블을 가져와 SetGameItemDataTable을 호출해 주는 부분은 게임 인스턴스의 생성자에서 구현하였다.
아마 다른 일이 없다면 여기서 인벤토리가 생성되어 데이터 테이블이 세팅될 것이다.
void UInvenMgr::SetGameItemDataTable(UDataTable* _ItemDataTable)
{
m_ItemTable = _ItemDataTable;
// 데이터 테이블 안에있는 모든 정보를 TArray 에 넣는다.
FString str;
TArray<FGameItemInfo*> arrTableData;
m_ItemTable->GetAllRows<FGameItemInfo>(str, arrTableData);
// 테이블 안에 있는 아이템 정보를 아이템 ID 를 Key 로 하는 TMap 에 넣는다.
for (int32 i = 0; i < arrTableData.Num(); ++i)
{
m_mapItemInfo.Add(arrTableData[i]->ID, *arrTableData[i]);
}
}
SetGameItemDataTable함수 안에서는 데이터 테이블을 배열로 변환하고 ID에 구조체를 매핑시켜 TMap 변수에 저장하였다.
인벤토리에 아이템을 넣는 기능
void UInvenMgr::AddGameItem(EITEM_ID _ID)
{
// 습득한 아이템 아이디에 해당하는 아이템 정보를 가져온다.
FGameItemInfo* pItemInfo = m_mapItemInfo.Find(_ID);
if (nullptr == pItemInfo)
{
LOG(LogTemp, Error, TEXT("ITME ID 에 해당하는 아이템 정보 찾을 수 없음"));
return;
}
// 아이템 타입에 맞는 백팩에 접근 후, 해당 아이템을 이미 보유하고있는지 확인
FItemStack* pItemStack = m_BackPack[(int32)pItemInfo->TYPE].Find(_ID);
if (nullptr == pItemStack)
{
m_BackPack[(int32)pItemInfo->TYPE].Add(_ID, FItemStack{ pItemInfo , 1});
}
else
{
++pItemStack->Stack;
}
}
아이템을 획득할 때 호출하게 될 함수이다.
매개변수로 받은 ID로 매핑 된 정보 구조체를 찾아온다.
현재 아이템 목록에 해당 아이템의 ID가 이미 있다면 수량을 증가시키고
nullptr을 가리킨다면 타입에 맞춰, 해당 ID와 정보/수량 구조체인 FItemStack을 매핑하여 새로 추가해 준다.
인벤토리를 열면 아이템을 보여주는 기능
void UInvenMgr::OpenInventoryUI()
{
// 현재 게임모드를 체크
AUnreal_3thGameModeBase* GameMode = Cast<AUnreal_3thGameModeBase>(UGameplayStatics::GetGameMode(m_World));
if (!IsValid(GameMode))
return;
// 게임모드로 부터 메인 HUD 가져오기
UMainHUD_Base* MainHUD = GameMode->GetMainHUD();
// MainHUD 로부터 InventoryWidget(UI) 가져오기
UInventory_Base* InventoryWidget = MainHUD->GetInventoryWidget();
// InventoryWidget(UI) 이전 내용 클리어하기
InventoryWidget->Clear();
// InvenMgr 가 보유하고 있는 아이템목록을 전부 UI 로 보내기
for (int32 i = 0; i < (int32)EITEM_TYPE::END; ++i)
{
for (auto Iterator = m_BackPack[i].CreateConstIterator(); Iterator; ++Iterator)
{
UInvenItemData* pData = NewObject<UInvenItemData>();
pData->SetIconImgPath(Iterator.Value().ItemInfo->IconPath);
pData->SetItemName(Iterator.Value().ItemInfo->Description);
pData->SetItemCount(Iterator.Value().Stack);
InventoryWidget->AddItem(pData);
}
}
// InventoryWidget Visible
MainHUD->ShowInventoryUI(true);
}
인벤토리를 열면. 즉 I키를 누르면 호출할 함수이다.
인벤토리 위젯을 가져오고 원래 있던 정보를 싹 지워준다.(인벤토리 위젯에 리스트를 지워주는 함수 구현)
인벤토리의 모든 아이템의 정보 구조체를 가져와 위젯에 아이템 데이터로 만들고, 인벤토리 위젯의 AddItem함수를 호출하여 넣어준다. 이 부분은 어제 만든 캐릭터가 점프를 할 때마다 아이템을 추가하는 부분과 코드상으로 동일하다.
for (auto Iterator = m_BackPack[i].CreateConstIterator(); Iterator; ++Iterator)
이 부분은 TMap 자료구조를 순회하는 방법이라고 한다.
void UMainHUD_Base::ShowInventoryUI(bool _bShow)
{
if(_bShow)
m_Inventory->SetVisibility(ESlateVisibility::Visible);
else
m_Inventory->SetVisibility(ESlateVisibility::Hidden);
}
참고로 위젯을 보이게, 안보이게 하는 방법은 이렇다.
'언리얼 > Assortrack UE5' 카테고리의 다른 글
[언리얼] 학원 21일차: 툴팁, 마우스 커서, 빌보드 (0) | 2023.09.25 |
---|---|
[언리얼] 학원 20일차: 인벤토리 끄기(UMG Input) (0) | 2023.09.22 |
[언리얼] 학원 18일차: 액터 위 UI, 인벤토리(리스트) (0) | 2023.09.20 |
[언리얼] 학원 17일차: 버튼, RenderTexture (0) | 2023.09.19 |
[언리얼] 학원 16일차: UMG: 언리얼 UI (0) | 2023.09.18 |