首页 > 解决方案 > UE4 C++ 跨多个级别保存项目指针的库存 TArray

问题描述

我在 UE4 中有一个基本的库存系统,它使用指向我的自定义 Item 类的指针 TArray。它在单个级别中运行良好,但是当我打开一个新级别时,库存消失了。我查看了有关此问题的多个教程和帖子,并尝试了各种解决方案,包括将我的库存数组迁移到游戏实例,并创建一个保存数组副本的 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);

        }

在 GameMode 中加载回玩家库存

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);
}

标签: c++unreal-engine4

解决方案


我相信您可能已经从我们在评论中的讨论中发现了为什么会出现问题,但我会尝试用这个答案来结束我们的讨论。问题是您正试图在地图中保存指向演员的指针数组。但是,一旦您调用UGameplayStatics::OpenLevel以更改地图,地图中的演员就会被破坏。结果,该数组中的指针最终指向垃圾数据,这就是您的游戏崩溃的原因。

现在,有很多方法可以解决这个问题,但你最终将不得不保存有关演员的信息并重生他们。我在虚幻引擎论坛上发现,一种常见的方法是创建一个自定义类型的结构FArchive来获取有关这些参与者的信息,在您的情况下,关于AItem. 例如,一个被调用的结构AItemInfo将存储诸如演员的类、演员的变换、演员的名字等信息,以及TArray表示来自演员的其他数据的序列化字节流的成员(AItem)。TArray然后,使用对象将参与者序列化到该结构的成员变量中FMemoryWriter。请注意,通常您不会序列化有关参与者的所有信息,只会序列化标有SaveGameArIsSaveGame将结构中的变量设置为 true 时的属性说明符。在为AItem您要跟踪的每个实例执行此操作后,您可以将此结构的每个实例存储在自定义类AItemInfo中定义的数组中。USaveGame在你的情况下,它是UBatteryMan_SaveGame. 然后,您可以调用包含信息结构数组的实例UGameplayStatics::SaveGameToSlotUBatteryMan_SaveGame当您加载该实例时,您可以使用对象反序列化数组中每个结构中UBatteryMan_SaveGame的字节数组/序列,以便获取除了结构中已有的其他内容之外的参与者信息,并使用所有这些信息重新创建每个原始地图中需要的演员。AItemInfoFMemoryReader

这里有几个很好的链接可以帮助您入门:


推荐阅读