본문 바로가기
Unreal Engine

언리얼 엔진에서 게임 저장하기 (SaveGame, JSON 저장/불러오기 예제 포함)

by 브랑제리 2025. 5. 9.
반응형

게임 저장과 불러오기 시스템 구현법 (SaveGame 클래스, JSON 저장 예제 포함)

게임을 개발하다 보면 플레이어 진행 상황이나 상태를 저장하고, 다시 불러와야 하는 상황이 자주 생깁니다.
언리얼 엔진에서는 USaveGame 클래스를 기반으로 저장 시스템을 쉽게 구성할 수 있습니다.
이 글에서는 기본적인 SaveGame 클래스 사용법부터 JSON 저장/불러오기 예제까지 정리해보겠습니다.

1. SaveGame 클래스 만들기

UCLASS()
class UMySaveGame : public USaveGame
{
    GENERATED_BODY()

public:
    UPROPERTY()
    int32 PlayerLevel;

    UPROPERTY()
    FVector PlayerLocation;
};

저장할 데이터를 담을 클래스를 USaveGame을 상속받아 정의합니다. 구조체처럼 사용할 수 있습니다.

2. 저장하기 – SaveGameToSlot

void SavePlayerData()
{
    auto SaveGameInstance = Cast<UMySaveGame>(UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass()));
    if (SaveGameInstance)
    {
        SaveGameInstance->PlayerLevel = CurrentLevel;
        SaveGameInstance->PlayerLocation = Player->GetActorLocation();

        UGameplayStatics::SaveGameToSlot(SaveGameInstance, TEXT("PlayerSaveSlot"), 0);
    }
}

SaveGameToSlot() 함수는 내부적으로 .sav 파일을 자동 생성해 저장해줍니다. 따로 경로를 지정할 필요는 없습니다.

3. 불러오기 – LoadGameFromSlot

void LoadPlayerData()
{
    if (UGameplayStatics::DoesSaveGameExist(TEXT("PlayerSaveSlot"), 0))
    {
        auto LoadedGame = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("PlayerSaveSlot"), 0));
        if (LoadedGame)
        {
            CurrentLevel = LoadedGame->PlayerLevel;
            Player->SetActorLocation(LoadedGame->PlayerLocation);
        }
    }
}

LoadGameFromSlot()은 실패할 수 있으므로 항상 null 체크를 해주시는 것이 안전합니다.

4. JSON으로 저장하기

디버깅용이거나, 외부 툴과 연동할 데이터를 저장할 때는 JSON 형식이 유용합니다.

void SaveDataAsJson(const FString& FilePath, int32 PlayerLevel, FVector Location)
{
    TSharedPtr<FJsonObject> JsonRoot = MakeShared<FJsonObject>();
    JsonRoot->SetNumberField("PlayerLevel", PlayerLevel);

    auto LocObject = MakeShared<FJsonObject>();
    LocObject->SetNumberField("X", Location.X);
    LocObject->SetNumberField("Y", Location.Y);
    LocObject->SetNumberField("Z", Location.Z);

    JsonRoot->SetObjectField("PlayerLocation", LocObject);

    FString OutputString;
    TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
    FJsonSerializer::Serialize(JsonRoot.ToSharedRef(), Writer);

    FFileHelper::SaveStringToFile(OutputString, *FilePath);
}

5. JSON 불러오기 – Deserialize

위에서 저장한 JSON 파일을 다시 불러오고 싶다면 Deserialize() 함수를 사용하면 됩니다.

void LoadDataFromJson(const FString& FilePath)
{
    FString JsonStr;
    if (FFileHelper::LoadFileToString(JsonStr, *FilePath))
    {
        TSharedPtr<FJsonObject> JsonRoot;
        TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonStr);

        if (FJsonSerializer::Deserialize(Reader, JsonRoot) && JsonRoot.IsValid())
        {
            int32 PlayerLevel = JsonRoot->GetIntegerField("PlayerLevel");

            auto LocObject = JsonRoot->GetObjectField("PlayerLocation");
            FVector LoadedLoc;
            LoadedLoc.X = LocObject->GetNumberField("X");
            LoadedLoc.Y = LocObject->GetNumberField("Y");
            LoadedLoc.Z = LocObject->GetNumberField("Z");

            // 적용
            CurrentLevel = PlayerLevel;
            Player->SetActorLocation(LoadedLoc);
        }
    }
}

JSON 필드명이 정확히 일치하지 않거나 누락되었을 경우 예외는 발생하지 않지만, 값이 로드되지 않으니 주의가 필요합니다.

6. 언제 어떤 방식을 써야 할까요?

상황 추천 방식
일반적인 게임 저장 USaveGame 기반 저장
디버깅용 로그 저장 JSON
외부 툴과 연동 JSON
네트워크로 전송할 데이터 JSON or Struct Serialization

마무리

언리얼의 SaveGame 시스템은 기본적으로 간단하게 구성되어 있지만, 설계에 따라 응용 범위가 넓습니다.
저장 데이터가 많아지면 분리 저장을 고려하고, JSON은 보조 수단이나 외부 연동용으로 병행하는 게 좋습니다.

🔗 관련 공식 문서

SaveGame 시스템 공식 문서 (Epic Games)

반응형