c++ - 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);
}
解决方案
我相信您可能已经从我们在评论中的讨论中发现了为什么会出现问题,但我会尝试用这个答案来结束我们的讨论。问题是您正试图在地图中保存指向演员的指针数组。但是,一旦您调用UGameplayStatics::OpenLevel
以更改地图,地图中的演员就会被破坏。结果,该数组中的指针最终指向垃圾数据,这就是您的游戏崩溃的原因。
现在,有很多方法可以解决这个问题,但你最终将不得不保存有关演员的信息并重生他们。我在虚幻引擎论坛上发现,一种常见的方法是创建一个自定义类型的结构FArchive
来获取有关这些参与者的信息,在您的情况下,关于AItem
. 例如,一个被调用的结构AItemInfo
将存储诸如演员的类、演员的变换、演员的名字等信息,以及TArray
表示来自演员的其他数据的序列化字节流的成员(AItem
)。TArray
然后,使用对象将参与者序列化到该结构的成员变量中FMemoryWriter
。请注意,通常您不会序列化有关参与者的所有信息,只会序列化标有SaveGame
ArIsSaveGame
将结构中的变量设置为 true 时的属性说明符。在为AItem
您要跟踪的每个实例执行此操作后,您可以将此结构的每个实例存储在自定义类AItemInfo
中定义的数组中。USaveGame
在你的情况下,它是UBatteryMan_SaveGame
. 然后,您可以调用包含信息结构数组的实例UGameplayStatics::SaveGameToSlot
。UBatteryMan_SaveGame
当您加载该实例时,您可以使用对象反序列化数组中每个结构中UBatteryMan_SaveGame
的字节数组/序列,以便获取除了结构中已有的其他内容之外的参与者信息,并使用所有这些信息重新创建每个原始地图中需要的演员。AItemInfo
FMemoryReader
这里有几个很好的链接可以帮助您入门:
推荐阅读
- python - 如果查询集包含django中的数据,如何根据相关对象过滤查询集
- mysql - MySQL 将时间显示为文本
- magento - 管理员菜单不会滑出,配置菜单也不会打开。按钮也不起作用
- c# - 碰撞的统一问题-特定碰撞后碰撞不起作用
- android - 在 Android 中覆盖 MPChart 值
- java - ConcurrentHashMap 中的值抛出 NullPointerException
- javascript - for循环传递参数中的多个onchange效果
- javascript - 将类添加到
- 如果有超过 2 个
- 嵌套的
- python - 如何修复 VSCode 和 Python 中的“无法导入 gurobipy”、未定义变量“模型”和未定义变量“GRB”?
- spring-boot - LoadBalanced RestTemplate 总是得到 java.net.SocketTimeoutException: Read timed out