【UE4】SaveGame存储系统

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;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章