1、C++创建enum,E开头
//表示Item的类型
UENUM(BlueprintType)
enum class EItemCategory :uint8 {
Consumable,
Equipment,
QuestItem,
Others,
Materials
};
2、C++创建Struct ,F开头
USTRUCT(BlueprintType)
struct FInventorySlot {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AbilityInfo")
TSubclassOf<class AItemBase>ItemClass; //对应的ItemClass类
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FItemInfo")
int32 Amount;//构造函数,按需拓展
FInventorySlot();};
3、创建UFUNCTION()
参见:https://www.tomlooman.com/ue4-ufunction-keywords-explained/
BlueprintCallable和const连用,成为pure function
BlueprintPure适用于数学函数
BlueprintImplementableEvent和BlueprintCallable连用
BlueprintNativeEvent
UFUNCTION(BlueprintImplementableEvent)
bool OnUse(); //据具体实现在蓝图中进行 返回Sucess
4、一个简单Inventory的数据结构:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
int32 AmountOfSlots;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
int32 MaxStackSize;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
TArray<FInventorySlot>Slots; //具体用于存储物品类型的数据结构
5、IsSlotEmpty
bool AInventoryBase::IsSlotEmpty(int32 index)
{
//为空返回true
return !Slots[index].ItemClass;
}
6、实现类似蓝图GetClassdefaults的功能,存在问题,待解决
FItemInfo AInventoryBase::GetItemInfoAtIndex(int32 index)
{
AItemBase* Item = Cast<AItemBase>(Slots[index].ItemClass->GetDefaultObject());
if (Item) { return Item->ItemInfo; }
else { return FItemInfo(); }
}
经过调试找到原因:ItemClass要加入非空判断
7、SearchEmptySlot
int32 AInventoryBase::SearchEmptySlot()
{
for (int index = 0; index < Slots.Num(); index++)
{
if (IsSlotEmpty(index))return index;
}
return -1;
}
8、SearchFreeStack
int32 AInventoryBase::SearchFreeStack(TSubclassOf<class AItemBase>ItemClass)
{
for (int index = 0; index < Slots.Num(); index++)
{
if (!IsSlotEmpty(index))
{ //找到且未满
if ((Slots[index].ItemClass == ItemClass)
&&Slots[index].Amount<MaxStackSize)
{
return index;
}
}
}
return -1;
}
9、AddItem
bool AInventoryBase::AddItem(TSubclassOf<class AItemBase> ItemClass, int32 Amount)
{
AItemBase* ItemToAdd = Cast<AItemBase>(ItemClass->GetDefaultObject());
if (ItemToAdd==nullptr) { return false; }
if (ItemToAdd->ItemInfo.CanbeStacked)
{
int32 FoundIndex = SearchFreeStack(ItemClass);
if (FoundIndex != -1)
{
//找到且能装,则更新数值即可
if (Slots[FoundIndex].Amount + Amount <= MaxStackSize) {
Slots[FoundIndex].Amount = Slots[FoundIndex].Amount + Amount;
OnSlotChanged(FoundIndex);//蓝图Event
return true;
}
else {
//找到一个格装不下
//为了避免递归>2,规定Amount<=MaxStackSize.
Amount = Slots[FoundIndex].Amount + MaxStackSize - Amount;
Slots[FoundIndex].Amount = MaxStackSize;
OnSlotChanged(FoundIndex);//蓝图Event
return AddItem(ItemClass, Amount);//这里执行物品栏中没有freestack那部分
}
}
else {
//物品栏中没有freestack
FoundIndex = SearchEmptySlot();
if (FoundIndex != -1)
{
//由于Amount <= MaxStackSize.更新数值和ItemClass
Slots[FoundIndex].Amount=Amount;
Slots[FoundIndex].ItemClass = ItemClass;
OnSlotChanged(FoundIndex);//蓝图Event
return true;
}
else {
//已满,需要清理
return false;
}
}
}
else {
//如果物品都是可以堆积的话,类似于魔女之泉,就用不到这里了
//如果不能堆积,则规定Amount为1
int32 FoundIndex = SearchEmptySlot();
if (FoundIndex != -1)
{
//由于Amount ==1.更新数值和ItemClass
Slots[FoundIndex].Amount = Amount;
Slots[FoundIndex].ItemClass = ItemClass;
OnSlotChanged(FoundIndex);//蓝图Event
return true;
}
else {
//已满,需要清理
return false;
}
}
return false;
}
10、RemoveItemAtIndex
//一般只有UI会调用
bool AInventoryBase::RemoveItemAtIndex(int32 index, int32 Amount)
{
if (IsSlotEmpty(index)) { return false; }
if (Amount <= 0) { return false; }
if (Slots[index].Amount > Amount)
{
Slots[index].Amount -= Amount;
OnSlotChanged(index);//只要改变就调用
return true;
}
else {
//移除数量大于等于已有数量,则清空
Slots[index].Amount = 0;
Slots[index].ItemClass = nullptr;
OnSlotChanged(index);//只要改变就调用
return true;
}
return false;
}