使用C++保存游戏

使用C++代码保存和加载游戏的方法

Windows
MacOS
Linux
本页面的内容

创建SaveGame对象

USaveGame 类将设置对象,可作为 Kismet/GameplayStatics.h 中声明的保存和加载函数的目标。

可基于 USaveGame 使用C++类向导新建类。

SaveGameCode.png

在本例中,新 USaveGame 类名为 UMySaveGame。要进行使用,在游戏模块标头文件中,将以下行添加 #include 指令后:

MyProject.h

#include "MySaveGame.h"
#include "Kismet/GameplayStatics.h"

标头

SaveGame 对象的标头文件中,可声明 SaveGame 要存储的变量。

UPROPERTY(VisibleAnywhere, Category = Basic)
FString PlayerName;

本例中还声明了将用于存储 SaveSlotNameUserIndex 默认值的变量,因此保存到此 SaveGame 对象的各类无需单独设置此类变量。此为可选步骤,若未修改默认值,将覆盖一个保存插槽。

MySaveGame.h

#pragma once

#include "GameFramework/SaveGame.h"
#include "MySaveGame.generated.h"

/**
 * 
 */
UCLASS()
class [PROJECTNAME]_API UMySaveGame : public USaveGame
{
    GENERATED_BODY()

    public:

    UPROPERTY(VisibleAnywhere, Category = Basic)
    FString PlayerName;

    UPROPERTY(VisibleAnywhere, Category = Basic)
    FString SaveSlotName;

    UPROPERTY(VisibleAnywhere, Category = Basic)
    uint32 UserIndex;

    UMySaveGame();
};

SaveGame 对象的源文件通常无需特定代码即可运行,在此处设置特定保存系统的其他功能时除外。

此例在类构造函数中定义了 SaveSlotNameUserIndex 的值,以便其可被其他游戏类读出和使用。

MySaveGame.cpp

// 版权所有 1998-2018 Epic Games, Inc。保留所有权利。

#include "[ProjectName].h"
#include "MySaveGame.h"

UMySaveGame::UMySaveGame()
{
    SaveSlotName = TEXT("TestSaveSlot");
    UserIndex = 0;
}

首先,(在 UGameplayStatics 库中)调用 CreateSaveGameObject,以获取新 UMySaveGame 对象。获取该对象后,使用要保存的数据进行填充。最后,调用 SaveGameToSlotAsyncSaveGameToSlot 将数据写出到设备。

异步保存

推荐使用 AsyncSaveGameToSlot 保存游戏。使用异步可防止帧率突然卡帧,使玩家不易觉察,并避免某些平台上出现认证问题。完成保存流程后,将使用插槽命名、用户索引和表明成败的 布尔值 调用委托(FAsyncSaveGameToSlotDelegate 类型)。

if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())))
{
    // 设置(可选)委托。
    FAsyncSaveGameToSlotDelegate SavedDelegate;
    // USomeUObjectClass::SaveGameDelegateFunction is a void function that takes the following parameters: const FString& SlotName, const int32 UserIndex, bool bSuccess
    SavedDelegate.BindUObject(SomeUObjectPointer, &USomeUObjectClass::SaveGameDelegateFunction);

    // 设置savegame对象上的数据。
    SaveGameInstance->PlayerName = TEXT("PlayerOne");

    // 启动异步保存进程。
    UGameplayStatics::AsyncSaveGameToSlot(SaveGameInstance, SlotNameString, UserIndexInt32, SavedDelegate);
}

同步保存

SaveGameToSlot 足以应对小型SaveGame格式,暂停时或在菜单中即可保存游戏。其简单易用,可即时保存游戏并返回表明成败的 布尔值。对于较大数据量,或要在玩家与游戏世界积极互动时自动保存游戏,建议使用 AsyncSaveGameToSlot

if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())))
{
    // 设置savegame对象上的数据。
    SaveGameInstance->PlayerName = TEXT("PlayerOne");

    // 即时保存游戏。
    if (UGameplayStatics::SaveGameToSlot(SaveGameInstance, SlotNameString, UserIndexInt32))
    {
        // 成功保存。
    }
}

二进制保存

可使用 SaveGameToMemory 函数将SaveGame对象传输到内存。此函数仅支持同步操作,但快于保存到驱动器。调用器将提供存储数据缓冲区(TArray<uint8>&)的引用。成功时,函数返回true。

TArray<uint8> OutSaveData;
if (UGameplayStatics::SaveGameToMemory(SaveGameObject, OutSaveData))
{
    // 操作成功,OutSaveData现在包含SaveGame对象的二进制代表。
}

使用缓冲区(const TArray<uint8>&)、插槽命名和用户ID信息以调用 SaveDataToSlot,也可将二进制数据直接保存到文件,与 SaveGameToSlot 函数类似。与 SaveGameToMemory 相同,此函数仅支持同步操作,并返回 布尔值 表明成败。

if (UGameplayStatics::SaveDataToSlot(InSaveData, SlotNameString, UserIndexInt32))
{
    // 操作成功,已将InSaveData写入到由我们提供的插槽命名和用户ID定义的存档文件。
}

异步加载

使用 AsyncLoadGameFromSlot 执行异步加载时,必须提供回调委托,以接收系统加载的数据。

// 设置委托。
FAsyncLoadGameFromSlotDelegate LoadedDelegate;
// USomeUObjectClass::LoadGameDelegateFunction 是采用下列参数的空隙函数: const FString& SlotName, const int32 UserIndex, USaveGame* LoadedGameData
LoadedDelegate.BindUObject(SomeUObjectPointer, &USomeUObjectClass::LoadGameDelegateFunction);
UGameplayStatics::AsyncLoadGameFromSlot(SlotName, 0, LoadedDelegate);

同步加载

若成功,LoadGameFromSlot 函数将创建并返回 USaveGame 对象。

// 检索并将USaveGame对象投射到UMySaveGame。
if (UMySaveGame* LoadedGame = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromSlot(SlotName, 0)))
{
    // 操作成功,LoadedGame现在将包含较早前保存的数据。
    UE_LOG(LogTemp, Warning, TEXT("LOADED:%s"), *LoadedGame->PlayerName);
}

二进制加载

可在文件中,使用 LoadDataFromSlot 并以原始二进制格式加载SaveGame数据。除开不创建SaveGame对象外,此函数与 LoadGameFromSlot 极为类似。同步操作尽可用于此类加载。

TArray<uint8> OutSaveData;
if (UGameplayStatics::LoadDataFromSlot(OutSaveData, SlotNameString, UserIndexInt32))
{
    // 操作成功,OutSaveData现在包含SaveGame对象的二进制代表。
}

还可通过调用 LoadGameFromMemory,将此二进制数据转换为SaveGame对象。此才做为同步调用,成功时返回新的 USaveGame 对象,失败时返回空指针。

if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(LoadGameFromMemory(InSaveData)))
{
    // 操作成功,SaveGameInstance将能投射到预期类型(UMySaveGame)。
}
Select Skin
Light
Dark

欢迎来到全新虚幻引擎4文档站!

我们正在努力开发新功能,包括反馈系统,以便您能对我们的工作作出评价。但它目前还未正式上线。如果您对此页面有任何意见与在使用中遭遇任何问题,请前往文档反馈论坛告知我们。

新系统上线运行后,我们会及时通知您的。

发表反馈意见