多个项目指针的UE4C++存储清单

多个项目指针的UE4C++存储清单,c++,unreal-engine4,C++,Unreal Engine4,在UE4中,我有一个基本的库存系统,使用指向我的自定义项目类的指针数组。它在单个关卡中运行良好,但当我打开一个新关卡时,库存就会消失。我已经阅读了关于这个问题的多个教程和帖子,并尝试了各种解决方案,包括将我的库存阵列迁移到游戏实例,以及创建一个保存阵列副本的SaveGame类,该副本在打开关卡之前保存,在打开关卡之后加载 在所有这些之后,库存仍然消失。我的代码已经改变了很多,所以可能没有多大帮助,但下面是我当前解决方案的一些片段 字符头中的声明 UPROPERTY(EditAnywhere, B

在UE4中,我有一个基本的库存系统,使用指向我的自定义项目类的指针数组。它在单个关卡中运行良好,但当我打开一个新关卡时,库存就会消失。我已经阅读了关于这个问题的多个教程和帖子,并尝试了各种解决方案,包括将我的库存阵列迁移到游戏实例,以及创建一个保存阵列副本的SaveGame类,该副本在打开关卡之前保存,在打开关卡之后加载

在所有这些之后,库存仍然消失。我的代码已经改变了很多,所以可能没有多大帮助,但下面是我当前解决方案的一些片段

字符头中的声明

UPROPERTY(EditAnywhere, BlueprintReadWrite)
    TArray<AItem*> Inventory_Space;
SaveGame中的声明

UPROPERTY(SaveGame)
    TArray<AItem*> Inventory_Save;
字符实现中的保存和加载函数

void ABatteryManPlayer::SaveInventory()
{
    
    UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
        (UGameplayStatics::CreateSaveGameObject(UBatteryMan_SaveGame::StaticClass()));

    for (int i = 0; i < INVENTORY_SIZE; i++) {
        SaveInstance->Inventory_Save[i] = Inventory_Space[i];
    }
    
    UGameplayStatics::SaveGameToSlot(SaveInstance, TEXT("Slot0"), 0);
}

void ABatteryManPlayer::LoadInventory()
{
    
    UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
        (UGameplayStatics::CreateSaveGameObject(UBatteryMan_SaveGame::StaticClass()));

    UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
        (UGameplayStatics::LoadGameFromSlot("Slot0",0));

    for (int i = 0; i < INVENTORY_SIZE; i++) {
        Inventory_Space[i] = SaveInstance->Inventory_Save[i];
    }
}
CurrentTime--;
    if (CurrentTime == 0) {

        SaveInventory();
        Instance->Levels_Complete++;

        if (Instance->Levels_Complete < Instance->NUM_LEVELS) {

            FName Level_Name = FName(TEXT("Level_" + FString::FromInt(++Instance->Levels_Complete)));
            UGameplayStatics::OpenLevel(this, Level_Name, false);

        }
游戏计时器转到0字符实现后保存

void ABatteryManPlayer::SaveInventory()
{
    
    UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
        (UGameplayStatics::CreateSaveGameObject(UBatteryMan_SaveGame::StaticClass()));

    for (int i = 0; i < INVENTORY_SIZE; i++) {
        SaveInstance->Inventory_Save[i] = Inventory_Space[i];
    }
    
    UGameplayStatics::SaveGameToSlot(SaveInstance, TEXT("Slot0"), 0);
}

void ABatteryManPlayer::LoadInventory()
{
    
    UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
        (UGameplayStatics::CreateSaveGameObject(UBatteryMan_SaveGame::StaticClass()));

    UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
        (UGameplayStatics::LoadGameFromSlot("Slot0",0));

    for (int i = 0; i < INVENTORY_SIZE; i++) {
        Inventory_Space[i] = SaveInstance->Inventory_Save[i];
    }
}
CurrentTime--;
    if (CurrentTime == 0) {

        SaveInventory();
        Instance->Levels_Complete++;

        if (Instance->Levels_Complete < Instance->NUM_LEVELS) {

            FName Level_Name = FName(TEXT("Level_" + FString::FromInt(++Instance->Levels_Complete)));
            UGameplayStatics::OpenLevel(this, Level_Name, false);

        }
在游戏模式下加载回玩家目录

void ABatteryMan_GameMode::BeginPlay() {
    Super::BeginPlay();

    ABatteryManPlayer* Player = Cast<ABatteryManPlayer>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
    Player->LoadInventory();

    FTimerHandle UnusedHandle;
    GetWorldTimerManager().SetTimer(
        UnusedHandle, this, &ABatteryMan_GameMode::SpawnPlayerRecharge, FMath::RandRange(2,5), true);
}

我相信您可能已经从我们在评论中的讨论中发现了问题的原因,但我将尝试用这个答案结束我们的讨论。问题是您试图在映射中保存指向参与者的指针数组。但是,一旦调用ugameplaystics::OpenLevel以更改地图,地图中的参与者就会被销毁。结果,该数组中的指针最终指向垃圾数据,这就是游戏崩溃的原因

现在,有很多方法可以做到这一点,但你最终必须保存有关演员的信息并让他们重生。我在Unreal Engine论坛上发现,一种常见的方法是创建FArchive类型的自定义结构,以获取有关这些参与者的信息,例如关于AItem实例的信息。例如,一个名为AItemInfo的结构将存储诸如参与者的类、参与者的转换、参与者的名称等信息,以及一个TArray成员,该成员表示来自参与者AItem的其他数据的序列化bytestream。然后,使用FMemoryWriter对象将actor序列化到该结构的TArray成员变量中。请注意,当您将结构中的ArIsSaveGame变量设置为true时,通常不会序列化有关actor的所有信息,而只序列化使用SaveGame属性说明符标记的特定变量/属性。对要跟踪的每个AItem实例执行此操作后,可以将此AItemInfo结构的每个实例存储在自定义USAEGAME类中定义的数组中。在你的情况下,这是UBatteryMan_SaveGame。然后,可以在包含信息结构数组的UBatteryMan_SaveGame实例上调用ugameplaystics::SaveGameToSlot。加载UBatteryMan_SaveGame实例时,可以使用FMemoryReader对象反序列化数组中每个AItemInfo结构中的数组/字节序列,以便除了结构中已有的其他内容之外,还可以获取参与者信息,并使用所有这些信息从原始映射中重新创建所需的每个参与者

以下是几个可以帮助您入门的好链接:


在SaveInventory中调用SaveGameToSlot时,是否可以检查返回值以查看它是否返回true或false?这将说明游戏是否成功保存。另外,您是否在LoadInventory函数中输入了错误?因为您在同一范围内声明了SaveInstance变量两次。我打印了一条调试消息,它说保存成功。这也是一个打字错误,在调用SaveGameToSlot并在LoadInventory方法中检索/打印同一个整数变量之前,我一直在转换代码。AItem是否为AActor类型?您是否也可以尝试将一个整数变量附加到UBatteryMan_SaveGame*以供测试?我在游戏中测试了一个int32值,它保存并携带到下一级,但库存仍然没有。AItem确实从AActor继承。当我将物品添加到库存中时,参与者将被销毁,但物品的缩略图和统计信息对于它们达到的级别仍然可见/可用。