본문으로 건너뛰기

안동민 개발노트

본문 시작

저장 및 로드 기본 구현

SaveGame 클래스를 정의하고 슬롯에 데이터를 저장·불러와 게임을 다시 실행해도 상태가 유지되도록 구현합니다.

게임 개발에서 데이터 저장(Save)로드(Load) 기능은 필수적입니다.

플레이어가 게임을 껐다가 다시 켰을 때, 이전에 진행했던 상태를 그대로 이어서 플레이할 수 있어야 하기 때문이죠.

단순히 점수나 설정뿐만 아니라, 플레이어의 위치, 인벤토리, 퀘스트 진행도, 월드 상태 등 다양한 데이터를 저장하고 불러올 수 있어야 합니다.

언리얼 엔진은 이러한 저장 및 로드 기능을 쉽게 구현할 수 있도록 저장 게임 오브젝트(Save Game Object) 시스템을 제공합니다.

저장 및 로드 기본 구현

SaveGame 흐름은 저장할 변수, 슬롯 이름, 저장 실행 시점, 로드 실패 시 기본값을 분리해 플레이어 진행 상태를 다시 만들 수 있게 하는 구조입니다.

  1. 복원할 값 선별

    진행도·위치·인벤토리처럼 다시 계산할 수 없는 값만 고릅니다.

  2. SaveGame 객체에 복사

    현재 게임 상태를 저장 전용 객체에 복사하고 슬롯 버전을 함께 기록합니다.

  3. Save Game to Slot

    체크포인트나 메뉴 저장 이벤트에서 정해진 슬롯에 원자적으로 씁니다.

  4. Load 또는 기본값

    슬롯이 있으면 역직렬화하고, 없거나 깨졌으면 안전한 초기값으로 시작합니다.

  5. 세이브 데이터 검수 지점

    NO SLOT 첫 실행으로 보고 안전한 기본값을 만든 뒤 새 게임 경로로 보냅니다. WRITE 기존 정상 슬롯을 보존하고 실패를 UI로 알려 재시도할 수 있게 합니다. VERSION 버전을 읽어 마이그레이션하거나 호환할 수 없으면 명확히 안내합니다. RESTORE 잘못된 위치와 음수 체력 같은 값은 검증하고 안전 지점으로 보정합니다.

  6. 슬롯 없음

    NO SLOT 첫 실행으로 보고 안전한 기본값을 만든 뒤 새 게임 경로로 보냅니다.

  7. 저장 실패

    WRITE 기존 정상 슬롯을 보존하고 실패를 UI로 알려 재시도할 수 있게 합니다.

  8. 구버전 슬롯

    VERSION 버전을 읽어 마이그레이션하거나 호환할 수 없으면 명확히 안내합니다.

  9. 복원 불변식

    RESTORE 잘못된 위치와 음수 체력 같은 값은 검증하고 안전 지점으로 보정합니다.


저장 게임 오브젝트란 무엇인가?

저장 게임 오브젝트(Save Game Object)는 게임에 저장하고 싶은 모든 데이터를 담는 특별한 종류의 오브젝트입니다.

이 오브젝트는 게임이 종료되거나 레벨이 변경되어도 파괴되지 않고, 마치 파일처럼 디스크에 저장(직렬화)되었다가 필요할 때 다시 메모리로 로드(역직렬화)될 수 있습니다.

저장 게임 오브젝트는 다음과 같은 특징을 가집니다.

  • 영속성(Persistence): 게임 세션이 끝나도 데이터가 유지됩니다.
  • 사용자 정의 가능: 개발자가 저장하고 싶은 데이터(변수)를 직접 정의할 수 있습니다.
  • 블루프린트 접근성: 블루프린트에서 쉽게 생성하고 데이터를 읽고 쓸 수 있습니다.
  • 플랫폼 독립성: 내부적으로 파일 시스템을 다루는 복잡한 과정을 언리얼 엔진이 처리해주므로, 개발자는 저장/로드 로직에만 집중할 수 있습니다.

저장 게임 오브젝트 생성 및 정의

가장 먼저 할 일은 어떤 데이터를 저장할지 정의하는 것입니다.

이는 저장 게임 오브젝트 블루프린트를 생성하여 그 안에 저장할 변수들을 정의하는 방식으로 이루어집니다.

저장 게임 블루프린트 생성
  • 콘텐츠 브라우저에서 마우스 오른쪽 버튼을 클릭합니다.
  • 블루프린트 클래스(Blueprint Class)를 선택합니다.
  • 모든 클래스(All Classes)를 펼친 후 SaveGame을 검색하여 선택합니다.
  • 이름을 지정합니다. (예: BP_MySaveGame - 일반적으로 BP_ 접두사를 사용합니다.)
저장할 변수 추가
  • 생성된 BP_MySaveGame 블루프린트 에디터를 엽니다.
  • 변수 패널에서 저장하고 싶은 데이터를 나타내는 변수들을 추가합니다.
    • 예시
      • PlayerScore (Integer)
      • PlayerLocation (Vector)
      • UnlockedLevels (Array of Integer)
      • PlayerName (Text)
  • 컴파일하고 저장합니다.

이제 BP_MySaveGame은 게임 상태를 담을 수 있는 데이터 컨테이너가 되었습니다.


데이터 저장(Save) 기본 구현

SaveGame 저장·로드 검증 지도

저장과 로드는 SaveGame 오브젝트 생성에서 끝나지 않습니다. 슬롯 존재, 캐스팅 성공, 값 유효성, 월드 적용까지 한 번에 검증해야 합니다.

  1. 저장 객체

    Create SaveGame Object로 저장할 컨테이너를 만듭니다.

  2. 값 기록

    현재 점수, 위치, 진행 상태를 SaveGame 변수에 씁니다.

  3. 슬롯 저장

    Save Game to Slot의 성공값과 슬롯 이름을 확인합니다.

  4. 로드 검사

    Does SaveGame Exist와 Cast 결과를 분기합니다.

  5. 월드 복원

    드된 값을 실제 액터와 UI에 적용하고 출력으로 확인합니다.

데이터 저장 과정은 주로 플레이어의 입력(예: S 키), 특정 이벤트(예: 체크포인트 도달, 레벨 전환), 또는 게임 종료 시점에 이루어집니다.

저장 로직을 구현할 블루프린트 열기: (예: BP_PlayerCharacter 또는 BP_GameManager)

Create SaveGame Object 노드
  • Event S 키 입력(저장 버튼) 노드 뒤에 Create SaveGame Object 노드를 추가합니다.
  • Save Game Class 핀에 여러분이 만든 BP_MySaveGame을 지정합니다.
  • 이 노드는 새로운 BP_MySaveGame 인스턴스를 메모리에 생성하여 반환합니다.
데이터 채우기 (캐스팅 후 변수 설정)
  • Create SaveGame ObjectReturn Value 출력 핀에서 드래그하여 Cast To BP_MySaveGame 노드를 연결합니다. (생성된 오브젝트를 실제 클래스 타입으로 캐스팅하여 접근하기 위함입니다.)
  • Cast To BP_MySaveGameAs BP My Save Game 출력 핀에서 드래그하여 Set PlayerScore (또는 여러분이 정의한 다른 변수)와 같은 노드를 추가합니다.
  • 현재 게임 상태에서 가져온 값들(예: Get PlayerScore (Game Instance에서 가져온), Get ActorLocation 등)을 저장 게임 오브젝트의 변수들에 연결합니다.
Save Game to Slot 노드
  • 데이터를 모두 채운 후, Set 노드의 실행 핀 뒤에 Save Game to Slot 노드를 추가합니다.
  • SaveGame Object 핀에는 Cast To BP_MySaveGameAs BP My Save Game 출력 핀을 연결합니다.
  • Slot Name 핀에는 저장할 파일의 고유한 이름을 Text 형태로 입력합니다. (예: "SaveSlot1") 이 이름은 게임 내에서 저장 파일을 구분하는 데 사용됩니다.
  • User Index 핀은 주로 멀티플레이어 게임에서 여러 사용자의 저장을 구분할 때 사용됩니다. 싱글 플레이어 게임에서는 보통 0을 사용합니다.
  • Return Value (불리언)는 저장이 성공했는지 여부를 반환합니다.

데이터 로드(Load) 기본 구현

데이터 로드 과정은 주로 게임 시작 시(예: Event BeginPlay에서 로드 확인), 또는 메인 메뉴에서 이어하기 버튼을 눌렀을 때 이루어집니다.

로드 로직을 구현할 블루프린트 열기: (예: BP_PlayerCharacter 또는 BP_GameManager)

Does SaveGame Exist 노드 (선택 사항, 안정성)
  • 로드를 시도하기 전에, 먼저 해당 슬롯 이름으로 저장된 파일이 존재하는지 확인하는 것이 좋습니다.
  • Event BeginPlay (또는 로드 버튼 클릭 이벤트) 뒤에 Does SaveGame Exist 노드를 추가합니다.
  • Slot NameUser Index를 저장 시 사용했던 것과 동일하게 입력합니다.
  • 이 노드의 Return ValueBranch 노드의 Condition에 연결합니다.
    • True (저장 파일 존재): 로드 로직으로 진행합니다.
    • False (저장 파일 없음): 새 게임 시작 로직으로 진행하거나, 로드 실패 메시지를 출력합니다.
Load Game From Slot 노드
  • Branch 노드의 True 실행 핀 뒤에 Load Game From Slot 노드를 추가합니다.
  • Slot NameUser Index를 저장 시 사용했던 것과 동일하게 입력합니다.
  • 이 노드는 저장된 파일이 있다면 BP_MySaveGame 인스턴스를 메모리로 로드하여 반환합니다.
로드된 데이터 활용 (캐스팅 후 변수 가져오기)
  • Load Game From SlotReturn Value 출력 핀에서 드래그하여 Cast To BP_MySaveGame 노드를 연결합니다.
  • Cast To BP_MySaveGameAs BP My Save Game 출력 핀에서 드래그하여 Get PlayerScore, Get PlayerLocation 등 저장했던 변수들을 가져옵니다.
  • 가져온 값들을 현재 게임 오브젝트의 변수(예: Set PlayerScore (Game Instance의), Set ActorLocation)에 연결하여 게임 상태를 복원합니다.
  • 예시: Set ActorLocation 노드를 연결하여 플레이어의 위치를 로드된 PlayerLocation으로 설정합니다.

로드 로직은 저장 파일이 항상 정상적으로 존재한다고 가정하지 않는 것이 중요합니다.

아래 흐름처럼 파일 존재 여부, 로드 결과, 캐스팅 결과, 실제 값의 유효성을 단계별로 확인하면 첫 실행이나 슬롯 손상 상황에서도 새 게임 기본값으로 안전하게 이어갈 수 있습니다.

SaveGame 로드 안정화 흐름

저장 파일 존재 여부, 타입 캐스팅, 값 유효성 확인을 분리하면 첫 실행과 손상된 슬롯에서도 기본값으로 안전하게 이어갈 수 있습니다.

  1. 1
    Does SaveGame Exist

    Start 저장에 사용한 Slot Name과 User Index로 파일 존재를 먼저 확인합니다.

  2. 2
    True / False 분기

    Branch True는 로드, False는 새 게임 초기화로 나누어 Access None을 피합니다.

  3. 3
    Load Game From Slot

    True 슬롯에서 SaveGame Object를 메모리로 불러옵니다.

  4. 4
    Cast To BP_MySaveGame

    Cast 로드 결과를 프로젝트에서 만든 SaveGame 타입으로 변환합니다.

  5. 5
    IsValid 후 값 복원

    Valid 점수, 위치, 해금 상태를 게임 인스턴스와 액터에 적용합니다.


주의사항 및 고급 활용

  • 저장할 데이터만 SaveGame Object에: 저장 게임 오브젝트에는 정말로 저장해야 할 데이터만 포함해야 합니다. 임시적인 데이터나 게임 내에서 실시간으로 계산되는 데이터는 포함하지 않는 것이 좋습니다.
  • 비동기 저장/로드: 대용량 데이터를 저장하거나 로드할 때 게임이 잠깐 멈추는 현상(프레임 드롭)이 발생할 수 있습니다. 이를 방지하기 위해 Async Save Game to Slot 또는 Async Load Game from Slot과 같은 비동기 노드를 사용할 수 있습니다. 이는 백그라운드에서 작업을 처리하므로 게임이 멈추지 않습니다.
  • 슬롯 이름 관리: 여러 개의 저장 파일을 지원하려면 각 저장 파일마다 고유한 Slot Name을 사용해야 합니다.
  • 유효성 검사: Cast 노드 사용 시 IsValid 핀을 활용하여 성공적으로 캐스팅되었는지, Access None 오류가 발생하지 않도록 항상 확인하는 습관을 들이는 것이 좋습니다.
  • 버전 관리: 게임 업데이트 시 저장 게임 오브젝트의 구조가 변경될 수 있습니다. 이때 이전 버전의 저장 파일을 불러올 때 문제가 발생할 수 있으므로, 저장 게임 오브젝트에 버전 변수를 추가하여 호환성을 관리하는 고급 기법도 고려해야 합니다.

저장 시스템은 노드 연결만으로 끝나는 기능이 아니라, 무엇을 저장하고 실패 시 어떻게 복구할지 정하는 운영 정책까지 함께 설계해야 안정적입니다.

저장할 값과 복원 규칙을 같이 정한다

SaveGame 오브젝트에는 진행 결과를 담고, 계산 과정이나 임시 상태는 로드 후 다시 만들어지도록 분리합니다.

  1. 1
    저장 대상

    what 점수, 위치, 해금 목록처럼 다음 실행에서도 유지되어야 하는 결과 값만 넣습니다.

  2. 2
    저장 시점

    when 체크포인트, 메뉴 저장, 레벨 전환처럼 플레이어가 납득할 수 있는 순간을 정합니다.

  3. 3
    복원 실패

    fallback 파일 없음, 캐스팅 실패, 값 누락 시 새 게임 기본값으로 이어지는 경로를 준비합니다.

  4. 4
    슬롯 운영에서 함께 고정할 값

    Slot Name 저장 파일을 구분하는 프로젝트 규칙 User Index 싱글 플레이는 보통 0으로 통일 Async Node 큰 데이터는 멈춤을 줄이기 위해 비동기 처리 Version 업데이트 후 기본값 보정의 기준

처음 구현할 때는 큰 시스템보다 작은 저장-로드 루프를 먼저 통과시키는 편이 안전합니다.

처음 저장 기능은 작은 루프로 통과시킨다

SaveGame 변수를 많이 늘리기 전에, 한 슬롯에서 저장과 로드가 같은 값을 재현하는지 짧은 루프로 확인합니다.

  1. Create

    BP_MySaveGame 오브젝트를 생성하고 캐스팅합니다.

  2. Fill

    점수, 위치, 해금 목록처럼 작은 값부터 채웁니다.

  3. Save

    Slot1과 User Index 0으로 저장 성공 여부를 받습니다.

  4. Load

    파일 존재 여부를 확인한 뒤 같은 슬롯에서 읽습니다.

  5. Apply

    드된 값을 현재 캐릭터와 게임 매니저에 적용합니다.

저장 및 로드 기능은 게임의 핵심적인 부분이며, 이 저장 게임 오브젝트 시스템을 통해 비교적 쉽게 구현할 수 있습니다.

복잡한 게임에서는 저장해야 할 데이터가 많아지므로, 데이터를 어떻게 구조화하고 어떤 시점에 저장/로드할지 신중하게 설계하는 것이 중요합니다.


이번 절에서는 언리얼 엔진의 저장 게임 오브젝트를 활용한 데이터 저장 및 로드의 기본 구현 방법에 대해 알아보았습니다.

이 기능은 플레이어의 진행 상황을 유지하고 몰입감을 높이는 데 필수적입니다.

마지막으로 SaveGame 노드를 연결할 때 확인해야 할 저장 슬롯, 캐스팅, 기본값 복구 기준을 정리합니다.

SaveGame 저장과 로드 검증 루틴

BP_SaveGame에 넣을 값, 슬롯 이름, 로드 실패 시 기본값을 분리하면 저장 흐름을 재현하기 쉽습니다.

  1. 1
    저장은 스냅샷, 로드는 적용 순서

    현재 체력, 위치, 인벤토리 같은 값을 저장 오브젝트에 복사하고, 로드 후에는 캐스팅 성공 여부를 확인한 뒤 액터에 다시 적용합니다. 01 SaveSlotName과 UserIndex를 변수로 고정해 저장 버튼, 자동 저장, 로드 버튼이 같은 위치를 바라보게 합니다. 02 Create Save Game Object로 BP_SaveGame을 만들고 변수 값을 채운 뒤 Save Game to Slot의 반환값을 확인합니다. 03 Does Save Game Exist 뒤에 Load Game from Slot과 Cast To BP_SaveGame을 연결하고 실패 시 새 게임 기본값을 사용합니다.

  2. 2
    저장은 스냅샷, 로드는 적용 순서

    현재 체력, 위치, 인벤토리 같은 값을 저장 오브젝트에 복사하고, 로드 후에는 캐스팅 성공 여부를 확인한 뒤 액터에 다시 적용합니다.

  3. 3
    슬롯 계약

    SaveSlotName과 UserIndex를 변수로 고정해 저장 버튼, 자동 저장, 로드 버튼이 같은 위치를 바라보게 합니다.

  4. 4
    저장 노드

    Create Save Game Object로 BP_SaveGame을 만들고 변수 값을 채운 뒤 Save Game to Slot의 반환값을 확인합니다.

  5. 5
    로드 노드

    Does Save Game Exist 뒤에 Load Game from Slot과 Cast To BP_SaveGame을 연결하고 실패 시 새 게임 기본값을 사용합니다.

저장과 로드 흐름을 슬롯 기준으로 점검하는 루틴을 추가합니다.

SaveGame 저장은 슬롯 이름과 저장할 값을 먼저 고정한다

저장 루틴은 객체 생성, 필드 채우기, 슬롯 기록, 성공 확인의 네 구간으로 읽는다.

  1. Create SaveGame

    USaveGame 기반 객체 생성

  2. Fill Fields

    점수, 위치, 옵션 값을 복사

  3. Choose Slot

    Player01, AutoSave 같은 이름 결정

  4. SaveGameToSlot

    디스크에 쓰기 요청

  5. Result Branch

    성공/실패 메시지 처리

점검기준
저장 대상직렬화 가능한 값만 필드에 넣는다.
나쁜 신호현재 Actor 참조를 그대로 SaveGame 객체에 넣는다.

저장과 로드는 SaveGame 오브젝트 생성에서 끝나지 않고, 슬롯 관리와 로드 후 월드 상태 적용까지 이어져야 합니다.

Save와 Load는 같은 슬롯을 쓰되 책임이 반대다

Save는 현재 상태를 파일에 쓰고, Load는 파일 값을 읽어 월드와 UI에 다시 주입한다.

  1. Save 루틴

    Create SaveGame 객체 생성 Copy 현재 상태를 필드에 복사 Write 정해진 SlotName에 저장

  2. Load 루틴

    Exists? 슬롯 존재 여부 확인 Read LoadGameFromSlot으로 객체 복원 Apply 월드 Actor와 UI를 값으로 갱신

검수의미
공유 기준SlotName과 UserIndex는 Save/Load가 같은 값을 써야 한다.
검수Load 실패 때 새 게임 기본값으로 돌아가는 경로가 있어야 한다.