SaveGame存储系统
使用SaveGame存储游戏到本地的逻辑和方法都很简单,涉及两个部分SaveGame对象,以及存储、加载方法。下面我们一一讲解。
一、SaveGame对象
首先,我们要创建一个继承USaveGame的类。我们需要在这个类的实例中保存需要持久化到磁盘的游戏数据,然后调用存储方法,将其写入磁盘。所以,我们在自定义USaveGame类中声明需要持久化的变量。一般,这些变量最好加个BlueprintReadWrite的宏,这样,我们也可以在蓝图中对这些变量进行修改或读取。
其实,到这里,这个类的基本介绍就完了。- - 其实,这个类就是将我们的对象序列化保存,然后反序列化到对象。
下面给出ActionRPG中的示例
namespace ERPGSaveGameVersion
{
enum type
{
//初始化版本
Initial,
//揹包修改
AddedInventory,
//物品修改
AddedItemData,
VersionPlusOne,
//最新版本
LatestVersion = VersionPlusOne - 1
};
}
UCLASS(BlueprintType)
class ACTIONRPG_API URPGSaveGame : public USaveGame
{
GENERATED_BODY()
public:
URPGSaveGame()
{
//当新创建一个SaveGame对象时,默认构造器会将其设置为最新版本
SavedDataVersion = ERPGSaveGameVersion::LatestVersion;
}
/** Map of items to item data */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = SaveGame)
TMap<FPrimaryAssetId, FRPGItemData> InventoryData;
/** Map of slotted items */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = SaveGame)
TMap<FRPGItemSlot, FPrimaryAssetId> SlottedItems;
/** 玩家的唯一ID */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = SaveGame)
FString UserId;
protected:
/** Deprecated way of storing items, this is read in but not saved out */
UPROPERTY()
TArray<FPrimaryAssetId> InventoryItems_DEPRECATED;
//当前SaveGame对象版本
UPROPERTY()
int32 SavedDataVersion;
/** 可以对SaveGame对象进行维护 */
virtual void Serialize(FArchive& Ar) override;
};
void URPGSaveGame::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
if (Ar.IsLoading() && SavedDataVersion != ERPGSaveGameVersion::LatestVersion)
{
if (SavedDataVersion < ERPGSaveGameVersion::AddedItemData)
{
// Convert from list to item data map
for (const FPrimaryAssetId& ItemId : InventoryItems_DEPRECATED)
{
InventoryData.Add(ItemId, FRPGItemData(1, 1));
}
InventoryItems_DEPRECATED.Empty();
}
SavedDataVersion = ERPGSaveGameVersion::LatestVersion;
}
}
二、存储、加载方法
UGameplayStatics中提供了几个静态方法,可以方便我们存储与加载序列化的SaveGame。
方法 | 说明 |
---|---|
bool UGameplayStatics::DoesSaveGameExist(FString SlotName, int32 UserIndex) | 指定SaveGame对象是否存在。 SlotName为存储对象的一个标识符,可以通过不同的标识符来获取不同的存储对象,UserIndex为玩家索引 |
USaveGame* UGameplayStatics::LoadGameFromSlot(FString SlotName, int32 UserIndex) | 加载指定SaveGame对象。 |
USaveGame* UGameplayStatics::CreateSaveGameObject(UClass* SaveGameClass) | 创建一个新的SaveGame对象。参数为SaveGame类的元数据 |
bool UGameplayStatics::SaveGameToSlot(USaveGame* SaveGame,int32 UserIndex) | 保存SaveGame对象到本地。 |
下面给出ActionRPG中的示例
bool URPGGameInstanceBase::LoadOrCreateSaveGame()
{
// 将SaveGame对象设为nullptr,则原来的SaveGame如果有效的话也将被GC
CurrentSaveGame = nullptr;
//判断当前SaveGame对象在本地是否有副本(是否保存到本地过),并且允许保存
if (UGameplayStatics::DoesSaveGameExist(SaveSlot, SaveUserIndex) && bSavingEnabled)
{ //从本地加载SaveGame对象
CurrentSaveGame = Cast<URPGSaveGame>(UGameplayStatics::LoadGameFromSlot(SaveSlot, SaveUserIndex));
}
//如果当前SaveGame对象有效
if (CurrentSaveGame)
{
//设置揹包物品
AddDefaultInventory(CurrentSaveGame, false);
//如果从本地加载成功,返回true
return true;
}
else
{
//如果磁盘没有副本,或者从磁盘加载失败,将创建一个新的SaveGame对象
CurrentSaveGame = Cast<URPGSaveGame>(UGameplayStatics::CreateSaveGameObject(URPGSaveGame::StaticClass()));
//设置揹包物品
AddDefaultInventory(CurrentSaveGame, true);
//如果当前SaveGame对象为新创建,将返回false
return false;
}
}