【问题标题】:UE4 C++ Inventory Items mutating after timeUE4 C++ Inventory Items 在一段时间后发生变化
【发布时间】:2021-04-07 18:58:06
【问题描述】:

我是 C++ 和 UE4 的新手。我来自 Java 背景。所以,请在这里温柔一点。 我目前正在尝试构建一个允许玩家拾取物品的游戏(我知道......完全独特的想法......)。这些项目存储在自定义库存项目对象的 TArray 中。每个库存项目对象代表项目属性以及当前在库存中的项目数量。 到目前为止,一切似乎都按设计运行。当我在游戏关卡中单击一个拾取项目时,它会将一个库存项目对象放入库存组件中。我已经查看了断点等,并且已经看到它正在正确分配库存项目和计数。 然而,大约一分钟后,TArray 中的库存项目对象突然发生变异,并包含所有垃圾数据(默认值甚至随机值)。 我猜这是由于垃圾收集或其他原因。我不知道如何解决它。我已尝试更改库存项目的创建方式,但似乎没有任何区别。

这里是 InventoryComponent.h 中相关信息的声明:

private:
    /* This is a pointer to the character that owns the inventory component */
    class APilferCharacter* OwningCharacter;

    /* These are the items that are currently in the inventory */
    class TArray<class UInventoryItem*> Items;

    class UInventoryItem* CreateInventoryItem(TSubclassOf<class UInventoryItem> InventoryItemClass);

public:
    /* 
    Adds a given number of the specified item to the inventory 
    Returns the actual number of items added (May be less than the requested amount if there is not enough space)
    */
    UFUNCTION(BlueprintCallable, Category = "Inventory")
        uint8 AddItem(TSubclassOf<class UInventoryItem> InventoryItemClass, uint8 count = 1);

以下是将库存项目添加到 UInventoryComponent 的代码:

UInventoryComponent::UInventoryComponent()
{
    MaxArrows = 15;
    MaxPotions = 3;
    this->Items.SetNum(0);
}

UInventoryItem* UInventoryComponent::CreateInventoryItem(TSubclassOf<UInventoryItem> InventoryItemClass)
{
    UInventoryItem* InventoryItem = NewObject<UInventoryItem>(this, InventoryItemClass);
    InventoryItem->OwningInventory = this; 
    InventoryItem->World = GetWorld();
    return InventoryItem;
}

uint8 UInventoryComponent::AddItem(TSubclassOf<UInventoryItem> InventoryItemClass, uint8 count)
{
    uint8 actualAddedCount = 0;
    if (count > 0) {
        UInventoryItem* itemToAdd = CreateInventoryItem(InventoryItemClass);
        UInventoryItem* existingItem = GetItemBySubType(itemToAdd->GetInventoryItemSubType());
        uint8 MaxItemCount = GetMaxItemsByType(itemToAdd->GetInventoryItemType());
        uint8 CurrentItemCount = 0;
        if (existingItem) {
            CurrentItemCount = existingItem->GetItemCount();
        }
        uint8 availableSpace = MaxItemCount - CurrentItemCount;
        actualAddedCount = std::min(count, availableSpace);
        itemToAdd->SetItemCount(actualAddedCount);

        if (existingItem)
        {
            actualAddedCount = existingItem->Add(actualAddedCount);
        }
        else
        {
            Items.Add(itemToAdd);
        }

        if (actualAddedCount > 0) {
            // Call the delegate to update the UI
            if (OnInventoryUpdated.IsBound())
            {
                OnInventoryUpdated.Broadcast();
            }
        }
    }
    return actualAddedCount;
}

如何使库存物品在组件的持续时间内持续存在?

提前致谢

【问题讨论】:

  • 所有 C++ 程序员的重要知识,对于那些来自托管语言的人来说更是如此:The rule of three/five/zero
  • 也就是说,不要在存储指针周围乱七八糟。尽可能将对象直接存储在容器中。低得多的内存管理负载,几乎总是比指针追逐空间多样化(因此缓存不友好)对象快。偶尔对直接存储的列表进行插入、删除和排序的成本通常与定期迭代指向对象的列表的成本相比相形见绌。
  • 如果您的容器不知道容器中实际有多少项目,并且您必须编写管理代码来跟踪,请不要编写代码。使用更智能的容器。虚幻可能有他们自己的为虚幻优化过的容器来执行此操作,但在普通的旧 C++ 中,您将从 std::vector 开始,只有在分析显示 vector 的简单性不够快后才更改为不同的容器。
  • 感谢您提供以上所有信息。我发现看到这一点非常有趣(我在其他资源中也看到过类似的信息,因为我研究了这个问题)。我最初认为这可能是问题的原因。然而,虚幻引擎被设计为几乎完全使用指针。整个框架是围绕指针构建的,除了原语之外,几乎所有使用过的都是指针。 (在处理内存分配、线程、GC 等方面有很多幕后魔法)。所以,我真的别无选择。
  • 我觉得有趣的是,当每个人似乎都在说这不是最好的性能时,框架是围绕指针构建的。但是,我认为其中很大一部分源于框架处理对象的方式。所以,唉,除非我绕过引擎提供的几乎所有资产,否则我会被很多指针卡住(如果有人知道不同,请告诉我)。

标签: c++ unreal-engine4


【解决方案1】:

好的!因此,在搜索互联网寻找解决方案后,我发现了这个网页: https://www.programmersought.com/article/40121301538/

当我阅读它时,我遇到了一些关于 UPROPERTY() 处理 TArrays 的 GC 的内容。然后我意识到我没有将 UPROPERTY() 添加到 TArray (我认为这没关系,因为它是私有财产)。所以,我想我会把它添加进去,看看它是否有所作为,瞧!它似乎奏效了!

所以,通过改变

/* These are the items that are currently in the inventory */
    class TArray<class UInventoryItem*> Items;

/* These are the items that are currently in the inventory */
    UPROPERTY()
    class TArray<class UInventoryItem*> Items;

该数组似乎正确地保存了这些值,并且在一分钟左右后没有将它们变成随机值。

【讨论】:

  • 正确,您需要在(几乎)任何指向从 UObject 派生的类的指针上添加 UPROPERTY 说明符,以防止它在仍被引用时被垃圾回收。
  • 如果组件是该字符的一部分,则 OwningCharacter 是多余的。使用GetOwner() 检索它。但是,如果您保留它,它也必须是 UPROPERTY。
猜你喜欢
  • 1970-01-01
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 2020-01-18
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多