You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unreal Engine中从UObject类创建实例的方法及DataTable物品类引用实例化报错解决方案

解决UE中TSubclassOf转实例的编译错误及物品掉落实例化问题

首先,你遇到的C2664错误核心原因很明确:TArray::Init()需要的是**UBattleItemBase的实例指针**,但你的DropItemClassTSubclassOf<UBattleItemBase>——这只是类的引用,不是实际的对象实例,所以直接传递肯定会类型不匹配。下面我给你一步步解决这个问题:

一、正确从UObject类创建实例的方法

在Unreal Engine中,要从TSubclassOf创建对象实例,你需要使用NewObject<UBattleItemBase>()函数,它会帮你实例化一个指定类的UObject对象。需要注意的是,创建实例时需要指定一个Outer对象(用来管理这个实例的生命周期,通常可以用当前角色对象、世界上下文或者其他持久化的UObject)。

修改你原来的掉落物品生成代码,替换掉ItemsToReturn.Init()的部分:

// 从按稀有度筛选的物品列表中随机选择一个条目
int SelectedIndex = FMath::RandRange(0, UsableRowIndexArray.Num() - 1);
// 从DataTable中获取该条目(记得加空指针检查!)
FItemDropRow* SelectedRow = ItemDropDataTable->FindRow<FItemDropRow>(UsableRowIndexArray[SelectedIndex], ContextString);
if (!SelectedRow || !SelectedRow->DropItemClass)
{
    // 处理空行或无效类的情况,返回空数组
    return TArray<UBattleItemBase*>();
}

// 根据DataTable行中定义的最小/最大掉落数量随机选择一个数值
int DropQuantity = FMath::RandRange(SelectedRow->MinDrop, SelectedRow->MaxDrop);

// 创建物品实例数组
TArray<UBattleItemBase*> ItemsToReturn;
ItemsToReturn.Reserve(DropQuantity); // 提前预留内存,优化性能

for (int i = 0; i < DropQuantity; ++i)
{
    // 创建物品实例,这里用当前角色作为Outer,你也可以用GetWorld()或者其他合适的UObject
    UBattleItemBase* NewItem = NewObject<UBattleItemBase>(this, SelectedRow->DropItemClass);
    if (NewItem)
    {
        ItemsToReturn.Add(NewItem);
    }
}

return ItemsToReturn;

二、为什么Instanced标记会导致DataTable无法编辑?

你尝试给DropItemClassInstanced标记是走入了误区:

  • Instanced属性修饰符是用来告诉Unreal,这个属性存储的是已经实例化的UObject对象,而不是类引用。
  • DataTable的行属性如果是Instanced的UObject,编辑器会要求你直接创建/选择一个实例,但你需要的是选择物品类(而不是提前创建好的实例),所以加了Instanced后,编辑器就不会显示类选择器,自然无法编辑了。

所以你的FItemDropRow结构体不需要修改,保持原来的定义就好:

USTRUCT(BlueprintType)
struct FItemDropRow : public FTableRowBase
{
    GENERATED_BODY()
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    TSubclassOf<UBattleItemBase> DropItemClass;
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    EItemRarity RarityTier;
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    int MinDrop;
    UPROPERTY(EditAnywhere, BlueprintReadOnly)
    int MaxDrop;
};

额外注意事项

  • 一定要加空指针检查FindRow可能返回空(比如行名不存在),DropItemClass也可能未设置,这些情况都要处理,避免运行时崩溃。
  • Outer对象的选择:如果你的物品需要跟随角色生命周期,用this(角色对象)作为Outer是合适的;如果物品需要独立存在(比如掉落地上的道具),可以用GetWorld()或者场景中的Actor作为Outer。
  • 如果UBattleItemBase是继承自AActor而不是UObject,那你需要用GetWorld()->SpawnActor<UBattleItemBase>()来创建实例,而不是NewObject——不过从你的代码看,它应该是UObject类型的物品数据类。

内容的提问来源于stack exchange,提问作者Laura L

火山引擎 最新活动