'게임 저장'의 의미는 게임에 따라 크게 다를 수 있지만, 플레이어가 게임을 종료했다가 중단한 시점에서부터 나중에 다시 시작할 수 있도록 만드는 일반적인 개념은 대부분의 최신 게임에 적용되어 있습니다. 제작하려는 게임의 타입에 따라 플레이어가 도달한 마지막 체크포인트나 플레이어가 발견한 아이템 등 몇 가지 기본적인 정보만 필요할 수도 있습니다. 또는 다른 인게임 캐릭터와 플레이어의 소셜 상호작용에 대한 상세 목록이나 다양한 퀘스트, 미션 목표, 서브플롯의 현재 상태 등 훨씬 더 자세한 정보가 필요할 수도 있습니다.
언리얼 엔진(UE)은 여러 플레이 세션 전반에서 유지해야 하는 모든 정보를 포함하여 게임에 필요한 사항을 충족하기 위해 생성하는 하나 이상의 커스텀 SaveGame 클래스를 중심으로 작동하는 저장 및 로딩 시스템을 제공합니다. 이 시스템은 저장된 게임 파일을 여러 개 유지하고 해당 파일에 서로 다른 SaveGame 클래스를 저장할 수 있도록 지원합니다. 이는 전역으로 잠금해제된 기능을 특정 플레이별 게임 데이터에서 분리하는 데 유용합니다.
Creating a SaveGame Object
The USaveGame class sets up an object that can be used as a target for the saving and loading functions declared in Kismet/GameplayStatics.h.
You can create a new class based on USaveGame using the C++ Class Wizard.
In this example, the new USaveGame class is called UMySaveGame. In order to use it, add the following lines to your game module's header file, after any other #include directives:
#include "MySaveGame.h"
#include "Kismet/GameplayStatics.h"Header
In the header file for your SaveGame object, you can declare any variables you want your SaveGame to store.
UPROPERTY(VisibleAnywhere, Category = Basic)
FString PlayerName;In this example, there are also variables declared that will be used to store default values for the SaveSlotName and the UserIndex, so that each class that saves to this
SaveGame object will not have to independently set those variables. This step is optional, and will cause there to be one save slot that gets overwritten if the default values are not changed.
#pragma once
#include "GameFramework/SaveGame.h"
#include "MySaveGame.generated.h"
/**
*
*/
UCLASS()
class [PROJECTNAME]_API UMySaveGame : public USaveGame
Source
Generally, the SaveGame object's source file does not need any particular code to function, unless your particular save system has additional functionality you would like to set up
here.
This example does define the values of SaveSlotName and UserIndex in the class constructor, so they can be read out and used by other gameplay classes.
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "[ProjectName].h"
#include "MySaveGame.h"
UMySaveGame::UMySaveGame()
{
SaveSlotName = TEXT("TestSaveSlot");
UserIndex = 0;
}게임 저장하기
SaveGame 클래스를 생성한 후, 게임 데이터를 저장하기 위한 변수로 채울 수 있습니다. 예를 들어, 플레이어의 점수를 저장하기 위한 integer 변수를 생성하거나 플레이어의 이름을 저장하기 위한 string 변수를 생성할 수 있습니다. 게임을 저장할 때, 현재 게임 월드의 정보를 SaveGame 오브젝트로 전송하고, 게임을 로드할 때는 SaveGame 오브젝트에서 캐릭터, 플레이어 컨트롤러, 게임 모드 등의 게임 오브젝트로 정보를 복사합니다.
First, call CreateSaveGameObject (from the UGameplayStatics library) to get a new UMySaveGame object. Once you have the object, you can populate it with the data you want to save. Finally, call SaveGameToSlot or AsyncSaveGameToSlot to write the data out to your device.
Asynchronous Saving
AsyncSaveGameToSlot is the recommended method for saving the game. Running asynchronously prevents a sudden framerate hitch, making it less noticeable to players and avoiding a possible certification issue on some platforms. When the save process is complete, the delegate (of type FAsyncSaveGameToSlotDelegate) will be called with the slot name, the user index, and a bool indicating success or failure.
if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())))
{
// Set up the (optional) delegate.
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);
// Set data on the savegame object.
SaveGameInstance->PlayerName = TEXT("PlayerOne");
Synchronous Saving
SaveGameToSlot is sufficient for small SaveGame formats, and for saving the game while paused or in a menu. It's also easy to use, as it simply saves the game immediately and returns a bool indicating success or failure. For larger amounts of data, or for auto-saving game while the player is still actively interacting with your game world, AsyncSaveGameToSlot is a better choice.
if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass())))
{
// Set data on the savegame object.
SaveGameInstance->PlayerName = TEXT("PlayerOne");
// Save the data immediately.
if (UGameplayStatics::SaveGameToSlot(SaveGameInstance, SlotNameString, UserIndexInt32))
{
// Save succeeded.
}
Binary Saving
You can transfer a SaveGame object to memory with the SaveGameToMemory function. This function only offers synchronous operation, but is faster than saving to a drive. The caller provides a reference to a buffer (a TArray<uint8>&) where the data will be stored. On success, the function returns true.
TArray<uint8> OutSaveData;
if (UGameplayStatics::SaveGameToMemory(SaveGameObject, OutSaveData))
{
// The operation succeeded, and OutSaveData now contains a binary represenation of the SaveGame object.
}You can also save binary data directly to a file, similar to the SaveGameToSlot function, by calling SaveDataToSlot with the buffer (a const TArray<uint8>&) and the slot name and user ID information. As with SaveGameToMemory, this function only offers synchronous operation, and returns a bool to indicate success or failure.
if (UGameplayStatics::SaveDataToSlot(InSaveData, SlotNameString, UserIndexInt32))
{
// The operation succeeded, and InSaveData has been written to the save file defined by the slot name and user ID we provided.
}개발 플랫폼에서 게임 저장 파일은 .sav 확장자를 사용하고 프로젝트의 Saved\SaveGames 폴더에 표시됩니다. 다른 플랫폼, 특히 콘솔에서는 해당 파일 시스템에 따라 달라집니다.
게임 로드하기
저장된 게임을 로드하려면 게임을 저장할 때 사용했던 세이브 슬롯 이름과 사용자 ID를 제공해야 합니다. 지정한 SaveGame이 존재하는 경우, 엔진이 여기에 포함된 데이터로 SaveGame 오브젝트를 채우고 베이스 SaveGame(USaveGame 클래스) 오브젝트로 반환합니다. 그런 다음 해당 오브젝트를 커스텀 SaveGame 클래스로 형변환하고 데이터에 액세스할 수 있습니다. SaveGame 타입에 포함된 데이터의 종류에 따라 오브젝트의 사본을 유지할 수도 있고, 아니면 데이터만 사용하고 오브젝트를 버릴 수도 있습니다.
저장과 마찬가지로, 동기식 또는 비동기식 로드도 수행할 수 있습니다. 데이터의 양이 많거나, 로딩 시간 동안 로딩 화면 또는 애니메이션을 사용하고 싶은 경우, 비동기 방식을 권장합니다. 로딩이 빠른 소량의 데이터에는 동기식 방식을 사용할 수 있습니다.
Asynchronous Loading
When loading asynchronously with AsyncLoadGameFromSlot, you must provide a callback delegate in order to receive the data that the system loads.
// Set up the delegate.
FAsyncLoadGameFromSlotDelegate LoadedDelegate;
// USomeUObjectClass::LoadGameDelegateFunction is a void function that takes the following parameters: const FString& SlotName, const int32 UserIndex, USaveGame* LoadedGameData
LoadedDelegate.BindUObject(SomeUObjectPointer, &USomeUObjectClass::LoadGameDelegateFunction);
UGameplayStatics::AsyncLoadGameFromSlot(SlotName, 0, LoadedDelegate);Synchronous Loading
The LoadGameFromSlot function will create and return a USaveGame object if it succeeds.
// Retrieve and cast the USaveGame object to UMySaveGame.
if (UMySaveGame* LoadedGame = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromSlot(SlotName, 0)))
{
// The operation was successful, so LoadedGame now contains the data we saved earlier.
UE_LOG(LogTemp, Warning, TEXT("LOADED: %s"), *LoadedGame->PlayerName);
}Binary Loading
You can load SaveGame data from a file in raw, binary form with LoadDataFromSlot. This function is very similar to LoadGameFromSlot, except that it does not create a SaveGame object. Only synchronous operation is available for this type of loading.
TArray<uint8> OutSaveData;
if (UGameplayStatics::LoadDataFromSlot(OutSaveData, SlotNameString, UserIndexInt32))
{
// The operation succeeded, and OutSaveData now contains a binary represenation of the SaveGame object.
}You can also convert this binary data to a SaveGame object by calling LoadGameFromMemory. This is a synchronous call, and returns a new USaveGame object upon success, or a null pointer on failure.
if (UMySaveGame* SaveGameInstance = Cast<UMySaveGame>(LoadGameFromMemory(InSaveData)))
{
// The operation succeeded, and SaveGameInstance was able to cast to type we expected (UMySaveGame).
}