안동민 개발노트 아이콘

안동민 개발노트

5장 : 기본 데이터 관리 기법

저장 및 로드 기본 구현

게임 개발에서 데이터 저장(Save)로드(Load) 기능은 필수적입니다. 플레이어가 게임을 껐다가 다시 켰을 때, 이전에 진행했던 상태를 그대로 이어서 플레이할 수 있어야 하기 때문이죠. 단순히 점수나 설정뿐만 아니라, 플레이어의 위치, 인벤토리, 퀘스트 진행도, 월드 상태 등 다양한 데이터를 저장하고 불러올 수 있어야 합니다.

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


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

저장 게임 오브젝트(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) 기본 구현

저장 및 로드 기본 구현에서 노드 흐름, 값 전달, 실행 결과를 정리한 것입니다.

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

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

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

저장 및 로드 기능은 게임의 핵심적인 부분이며, 이 저장 게임 오브젝트 시스템을 통해 비교적 쉽게 구현할 수 있습니다. 복잡한 게임에서는 저장해야 할 데이터가 많아지므로, 데이터를 어떻게 구조화하고 어떤 시점에 저장/로드할지 신중하게 설계하는 것이 중요합니다.


이번 절에서는 언리얼 엔진의 저장 게임 오브젝트를 활용한 데이터 저장 및 로드의 기본 구현 방법에 대해 알아보았습니다. 이 기능은 플레이어의 진행 상황을 유지하고 몰입감을 높이는 데 필수적입니다.

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

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

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