PART 4 · 강의 3/3

Save/Load 시스템

USaveGame 클래스를 활용한 게임 데이터 저장과 로드를 구현합니다

01

SaveGame 클래스

UE5의 직렬화 기반 세이브 시스템

UE5는 USaveGame 클래스를 기반으로 게임 데이터를 직렬화(Serialize)하여 파일로 저장합니다. 블루프린트에서 우클릭 > Blueprint Class > Save Game으로 생성합니다.

BP_SaveGame Structure BP_MySaveGame (Parent: SaveGame) // 저장할 데이터를 변수로 정의 ├─ PlayerName: String ├─ PlayerLevel: Integer ├─ PlayerLocation: Vector ├─ PlayerRotation: Rotator ├─ CurrentHealth: Float ├─ MaxHealth: Float ├─ Inventory: Array<S_ItemData> ├─ CompletedQuests: Array<Name> ├─ ActiveQuests: Map<Name, S_QuestProgress> ├─ PlayTime: Float └─ SaveTimestamp: DateTime

세이브/로드 핵심 노드

노드설명
Create Save Game ObjectSaveGame 인스턴스 생성 (메모리에만)
Save Game to Slot인스턴스를 파일로 저장
Load Game from Slot파일에서 인스턴스 로드
Does Save Game Exist세이브 파일 존재 확인
Delete Game in Slot세이브 파일 삭제
02

저장(Save) 구현

게임 데이터를 수집하여 파일로 저장하기

Save Implementation // 함수: SaveGame(SlotName: String, UserIndex: Integer) [Create Save Game Object] └─ Save Game Class: BP_MySaveGame │ └──> [Cast to BP_MySaveGame] │ ├──> [Set PlayerLocation] = GetActorLocation() ├──> [Set PlayerRotation] = GetActorRotation() ├──> [Set CurrentHealth] = HealthComponent.GetHealth() ├──> [Set Inventory] = InventoryComponent.GetAllItems() ├──> [Set PlayerLevel] = GetLevel() ├──> [Set SaveTimestamp] = Now() │ └──> [Save Game to Slot] ├─ Save Game Object: (위 인스턴스) ├─ Slot Name: "SaveSlot_1" ├─ User Index: 0 └─ Return Value: Boolean (성공 여부)
Slot Name 관리

Slot Name은 파일 이름으로 사용됩니다. 여러 세이브 슬롯을 지원하려면 "SaveSlot_1", "SaveSlot_2" 등으로 구분합니다. User Index는 로컬 멀티플레이어에서 플레이어를 구분하며, 싱글플레이어에서는 항상 0입니다.

03

로드(Load) 구현

저장된 데이터를 복원하여 게임 상태 재설정

Load Implementation // 함수: LoadGame(SlotName: String) [Does Save Game Exist] ├─ Slot Name: "SaveSlot_1" └─ Return: Boolean │ └──> [Branch] ├─ True ──> [Load Game from Slot] │ ├─ Slot Name: "SaveSlot_1" │ ├─ User Index: 0 │ └─ Return: SaveGame │ │ │ └──> [Cast to BP_MySaveGame] │ │ │ ├──> [SetActorLocation](PlayerLocation) │ ├──> [SetActorRotation](PlayerRotation) │ ├──> [SetHealth](CurrentHealth) │ ├──> [RestoreInventory](Inventory) │ └──> [SetLevel](PlayerLevel) │ └─ False ──> [Print "No save file found"]

비동기 저장/로드

대용량 데이터의 경우 Async Save Game to SlotAsync Load Game from Slot을 사용하면 메인 스레드를 블로킹하지 않습니다.

Async Save/Load // 비동기 저장 [Async Save Game to Slot] ├─ Save Game Object ├─ Slot Name ├─ User Index └─ Delegate: ├─ On Success ──> [Show "Saved!" Notification] └─ On Failure ──> [Show "Save Failed" Error] // 비동기 로드 [Async Load Game from Slot] ├─ Slot Name ├─ User Index └─ Delegate: ├─ On Success ──> (SaveGame Object 핀) ──> [Restore State] └─ On Failure ──> [Start New Game]
세이브 파일 위치

Windows에서 세이브 파일은 [프로젝트]/Saved/SaveGames/ 폴더에 .sav 확장자로 저장됩니다. 패키지된 게임에서는 %LocalAppData%/[프로젝트명]/Saved/SaveGames/에 저장됩니다.

04

실전 세이브 시스템 설계

Game Instance 활용과 세이브 매니저 패턴

Game Instance를 세이브 매니저로 활용

UGameInstance는 레벨 전환 시에도 유지되므로, 세이브 관리의 중앙 허브로 적합합니다.

Save Manager in GameInstance BP_GameInstance (Save Manager) // 변수 ├─ CurrentSaveData: BP_MySaveGame (Object Reference) ├─ CurrentSlotName: String = "SaveSlot_1"// 함수 ├─ SaveGame() │ ├─ 현재 게임 상태를 CurrentSaveData에 기록 │ └─ Save Game to Slot(CurrentSaveData, CurrentSlotName, 0) │ ├─ LoadGame() → Boolean │ ├─ Does Save Game Exist → Load Game from Slot │ └─ CurrentSaveData에 저장, 성공 여부 반환 │ ├─ GetSaveSlotInfo(SlotName) → S_SlotInfo │ └─ 슬롯별 메타데이터 (레벨, 플레이 시간, 스크린샷) │ └─ DeleteSave(SlotName) └─ Delete Game in Slot // 접근: Get Game Instance → Cast to BP_GameInstance

자동 저장 구현

Auto-Save Pattern // 체크포인트 Actor를 통한 자동 저장 BP_Checkpoint └─ BoxCollision (OnOverlapBegin) │ └──> [DoOnce] ──> [Get Game Instance] └──> [Cast to BP_GameInstance] └──> [SaveGame] └──> [Show "Auto Saved"]
저장할 수 없는 데이터

SaveGame에 Actor 참조를 직접 저장하면 안 됩니다 (로드 시 해당 Actor가 존재하지 않을 수 있음). 대신 Actor를 식별할 수 있는 Name, Transform, 클래스 정보를 저장하고 로드 시 재생성하세요. Widget, Material Instance 등의 런타임 오브젝트도 저장 불가합니다.

SUMMARY

핵심 요약

  • USaveGame 블루프린트에 저장할 변수를 정의하고, Save/Load Game to/from Slot으로 파일 입출력한다
  • Does Save Game Exist로 파일 존재를 먼저 확인한 후 로드한다
  • 대용량 데이터는 Async Save/Load를 사용하여 메인 스레드 블로킹을 방지한다
  • GameInstance는 레벨 전환 시 유지되므로 세이브 매니저로 적합하다
  • Actor 참조는 직접 저장할 수 없으며, 식별 가능한 데이터(Name, Transform)로 대체한다
  • 세이브 파일은 Saved/SaveGames/ 폴더에 .sav 형식으로 저장된다
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: 기본 세이브/로드 구현

USaveGame을 상속하는 BP_MySaveGame을 생성하고, PlayerName(String), HighScore(Integer), LastCheckpoint(Transform) 변수를 추가하세요. Save Game to Slot과 Load Game from Slot 노드를 사용하여 저장/불러오기를 구현하세요.

실습 2: 다중 슬롯 세이브 시스템

3개의 세이브 슬롯(Slot_1, Slot_2, Slot_3)을 관리하는 시스템을 만드세요. Does Save Game Exist로 슬롯 존재 여부를 확인하고, 각 슬롯의 저장 시간과 플레이 타임을 표시하는 UI를 구현하세요.

심화 과제

자동 저장(Auto Save) 시스템을 구현하세요. 타이머로 5분마다 자동 저장하고, 체크포인트 Trigger Volume 진입 시에도 저장합니다. 게임 설정(해상도, 볼륨, 키 바인딩)을 별도 슬롯에 저장하는 Settings Save 시스템도 분리 구현하세요.