1 把获取物品信息改为读取数据表
先创建结构,暂时有这几个属性:
USTRUCT(BlueprintType)
struct ARPG_CPLUS_API FMyItemData:public FTableRowBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int ItemId;//物品Id,唯一
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int MaxOwnedCnt;//最大堆叠数量
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString ItemBaseName;//物品名称
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UTexture2D* Texture;//物品图标
};
创建对应的数据表
实现Get函数:
FMyItemData UWarehouseManager::GetItemDataByItemId(int ItemId)
{
if(!ItemDataTable)return FMyItemData();
// 获取DataTable的所有行
TArray<FName> RowNames= ItemDataTable->GetRowNames();
// 遍历每一行
for (const auto& RowName : RowNames)
{
FMyItemData* RowData = ItemDataTable->FindRow<FMyItemData>(RowName,FString(""),true);
if (RowData->ItemId == ItemId)
{
return *RowData;
}
}
return FMyItemData();
}
把原来获取Texture的地方改为用这个函数:
2 编写Bag相关代码
2.1 BagSaveData
//BagSaveData.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/SaveGame.h"
#include "BagSaveData.generated.h"
struct FMyItemInfo;
/**
*
*/
UCLASS()
class ARPG_CPLUS_API UBagSaveData : public USaveGame
{
GENERATED_BODY()
public:
UBagSaveData();
UFUNCTION(BlueprintCallable)
TArray<FMyItemInfo> GetItemsInBag();
UFUNCTION(BlueprintCallable)
void SetItemsInBag(TArray<FMyItemInfo> InItems);
private:
UPROPERTY(EditDefaultsOnly)
TArray<FMyItemInfo> ItemsInBag;
};
//BagSaveData.cpp
#include "Items/BagSaveData.h"
#include "Items/WarehouseManager.h"
UBagSaveData::UBagSaveData()
{
}
TArray<FMyItemInfo> UBagSaveData::GetItemsInBag()
{
return ItemsInBag;
}
void UBagSaveData::SetItemsInBag(TArray<FMyItemInfo> InItems)
{
ItemsInBag = InItems;
}
2.2 BagManager
//BagManager.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "BagManager.generated.h"
struct FMyItemInfo;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ARPG_CPLUS_API UBagManager : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UBagManager();
UFUNCTION(BlueprintCallable)
void SaveData();
UFUNCTION(BlueprintCallable)
void LoadData();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "BagItemData")
UDataTable* ItemDataTable;
UPROPERTY(BlueprintReadOnly)
TArray<FMyItemInfo> ItemsInBag;
UFUNCTION(BlueprintCallable)
void LogMes();
UFUNCTION(BlueprintCallable)
void AddItemByArray(TArray<FMyItemInfo> ItemsToAdd);
UFUNCTION(BlueprintCallable)
void AddItemToBag(FMyItemInfo& ItemToAdd);
UFUNCTION(BlueprintCallable)
bool RemoveItemFromBag(int ItemId,int Subcnt);
UFUNCTION(BlueprintCallable)
FMyItemInfo GetItemInfoByItemId(int ItemId);
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
};
//BagManager.cpp
#include "Items/BagManager.h"
#include "Items/BagSaveData.h"
#include "Items/WarehouseManager.h"
#include "Kismet/GameplayStatics.h"
// Sets default values for this component's properties
UBagManager::UBagManager()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
//UE_LOG(LogTemp,Warning,TEXT("UBagManager Construct Start"));
LoadData();
//LogMes();
static ConstructorHelpers::FObjectFinder<UDataTable> DataTableAsset(TEXT("DataTable'/Game/Data/DataTable/ItemsData.ItemsData'"));
if (DataTableAsset.Succeeded())
{
ItemDataTable = DataTableAsset.Object;
//UE_LOG(LogTemp,Warning,TEXT("Item DataTable Load Success"));
}
//UE_LOG(LogTemp,Warning,TEXT("UBagManager Construct End"));
// ...
}
// Called when the game starts
void UBagManager::BeginPlay()
{
Super::BeginPlay();
LoadData();
}
// Called every frame
void UBagManager::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
void UBagManager::SaveData()
{
UBagSaveData* Save = Cast<UBagSaveData>(UGameplayStatics::CreateSaveGameObject(UBagSaveData::StaticClass()));
if (Save)
{
Save->SetItemsInBag(ItemsInBag);
if (UGameplayStatics::SaveGameToSlot(Save, FString("BagSaveData"), 0))
{
UE_LOG(LogTemp, Warning, TEXT("UBagManager-->Save Success"));
}
else
{
UE_LOG(LogTemp, Warning, TEXT("UBagManager-->Save Failed"));
}
}
}
void UBagManager::LoadData()
{
bool bIsExistSaveData=UGameplayStatics::DoesSaveGameExist(FString("BagSaveData"),0);
if(bIsExistSaveData)
{
UBagSaveData* save=Cast<UBagSaveData>(UGameplayStatics::LoadGameFromSlot(FString("BagSaveData"), 0));
ItemsInBag=save->GetItemsInBag();
UE_LOG(LogTemp,Warning,TEXT("UBagManager-->Loaded Success"));
}else
{
SaveData();
UE_LOG(LogTemp,Warning,TEXT("UBagManager-->Loaded Fail"));
}
}
void UBagManager::LogMes()
{
UE_LOG(LogTemp, Warning, TEXT("BagManager::LogMes-->Start,Num==%d"),ItemsInBag.Num());
for(FMyItemInfo& bagItem : ItemsInBag)
{
UE_LOG(LogTemp, Warning, TEXT("ID==%d CurrentOwnedCnt==%d DisplayName==%s"), bagItem.ItemId, (int)bagItem.CurrentOwnedCnt,*bagItem.DisplayName);
}
}
void UBagManager::AddItemByArray(TArray<FMyItemInfo> ItemsToAdd)
{
for(FMyItemInfo& bagItem : ItemsToAdd)
{
AddItemToBag(bagItem);
}
SaveData();
}
void UBagManager::AddItemToBag(FMyItemInfo& ItemToAdd)
{
bool bisFind=false;
for(FMyItemInfo& bagItem : ItemsInBag)
{
if(bagItem.ItemId == ItemToAdd.ItemId)
{
//TODO:限制最大堆叠
bagItem.CurrentOwnedCnt += ItemToAdd.CurrentOwnedCnt;
bisFind=true;
break;
}
}
if(!bisFind)
{
ItemsInBag.Add(ItemToAdd);
}
SaveData();
}
bool UBagManager::RemoveItemFromBag(int ItemId,int Subcnt)
{
for(FMyItemInfo& bagItem : ItemsInBag)
{
if(bagItem.ItemId == ItemId)
{
if(bagItem.CurrentOwnedCnt>Subcnt)
{
bagItem.CurrentOwnedCnt-=Subcnt;
SaveData();
UE_LOG(LogTemp, Warning, TEXT("UBagManager::RemoveItemFromBag Success! Cnt==%d"),(int)bagItem.CurrentOwnedCnt);
return true;//如果数量够的话就直接减
}
}
}
SaveData();
UE_LOG(LogTemp, Warning, TEXT("UBagManager::RemoveItemFromBag not Enough"));
return false;
}
FMyItemInfo UBagManager::GetItemInfoByItemId(int ItemId)
{
for(FMyItemInfo& bagItem : ItemsInBag)
{
if(bagItem.ItemId == ItemId)
{
//LogMes();
//UE_LOG(LogTemp,Warning,TEXT("GetItemInfoByItemId-->ItemId==%d,CurrentCnt==%d"),ItemId,(int)bagItem.CurrentOwnedCnt);
return bagItem;
}
}
return FMyItemInfo();
}
3 制作BagUI,动态生成物品格子
动态生成25个(测试用),5行5列,生成时设置行列填充比例都为1,这样GridPanel就能平均分配空间
添加到子项:
根据是否有数据来选择是否更新信息:
更新信息:
效果: