UnrealEngine

Unreal Engine 5 슬롯형 세이브 로드 기능 구현

murlocdev 2025. 6. 9. 14:34

먼저 세이브 해야할 데이터들을 구조체로 묶어서 BP_SaveGame에 저장했다

 

S_PlayerStat 생성
Player가 갖고있어야할 정보들을 구조체에 저장
BP_SaveGame 생성
BP_SaveGame의 변수들
BP_ThirdPersonCharacter의 변수에 구조체 추가, 다른 오브젝트는 플레이어가 갖고있지 않아도 될것이라 생각해서 SaveGame을 추가하지 않음
BP_GameInstance의 변수들. SavedData는 SaveGame을 저장하는 변수이고 IsNewGame은 NewGame과 LoadGame을 구별하기 위해 만들었다
WB_ESCMenu
WidgetSwitcher로 Save메뉴로 변경 가능
Switcher의 인덱스를 1로 바꾸면 Save Menu에 진입한다
Save를 클릭하면 Switcher의 인덱스가 1이되어 세이브 메뉴를 활성화 시키고 세이브 버튼을 누르면 그에 맞는 Index를 Save Function으로 입력
SaveFunction 함수
BPI_SaveGame의 함수들
Save의 구체적인 기능들은 BP_GameInstance에서 구현함
GetPlayerSave는 BP_ThirdPersonCharacter에서 구현했다. 매번 정보가 바뀔때마다 Player Stat을 저장하면 최적화에 나쁜 영향을 끼칠거라 판단했기 때문에 저장버튼을 누른것처럼 필요한 순간에만 BP_GameInstance에 저장하게 설계했다. 이 경우 BP_GameInstance의 BP_SaveGame 변수에 값들을 set 한 후에 SaveGame을 저장해야 정상적으로 저장파일이 데이터를 포함한 채로 만들어진다.
BP_GameInstance에 SaveGameData 까지 구현 완료. 혹시 몰라 Async Save Game도 미리 만들어뒀다
중단점을 걸어보면 세이브시 정상적으로 저장이 되는걸 확인할 수 있다
WB_MainMenu 구현, WB_ESCMenu와 마찬가지로 Switcher로 Load Menu를 활성화 시킬 수 있다
Level은 GameMap과 MenuMap이 있는데 처음 시작할땐 MainMap에서 메인메뉴만 활성화 되어있으므로 Level GameMap으로 바꿔준다. ESCMenu와 마찬가지로 switcher를 이용해 Load 메뉴를 활성화 가능하게 구현했다
각 버튼은 그에 맞는 Index를 set하고 savefile_index로 세이브파일 이름을 결정한다
NewGame과 구별하기위해 false로 설정해주고 Load해온 BP_SaveGame의 PlayerStat 구조체를 GameInstance의 PlayerStat 구조체로 set해준다. 그리고 저장할때 있었던 Level의 이름을 Open Level로 넘겨주어서 나중에 다른 맵 추가시에도 원할하게 로드 되도록 만들었다
OpenLevel이 끝나면 BP_ThirdPersonCharacter의 BeginPlay 이벤트로 가서 게임을 로드한 경우에만 인스턴스에 저장되어있는 값들을 가져오게 만들었다
BP_GameInstance의 GetGameData 인터페이스
BP_ThirdPersonCharacter의 UsePlayerSave 함수 구현. 저장된 Transform 좌표로 플레이어의 Actor를 set하고 카메라 시점도 Control Rotation으로 정해주고 나머지 정보들을 구조체 분할로 set해주었다
게임에서 Load를 하면 먼저 GameInstance에 BP_SaveGame값들을 set한 후, open level로 마지막으로 저장했던 맵을 불러온다. 여기서 바로 캐릭터의 stat에 넣어주면 아직 게임이 불러와지지 않았으므로 에러가 발생하기 때문에 캐릭터의 BeginPlay에서 load된 게임에 한해서만 GameInstance의 값을 set하도록 설정했다
정상적으로 BP_SaveGame의 값들이 Player Character에게 전달되는것을 확인했다
나중에 저장할 데이터가 늘어나면 간단하게 BP_SaveGame의 변수를 추가만 해주면 된다. 물론 그에 맞는 SaveLoad 기능을 추가해야한다.
세이브 로드 완성

세이브 로드를 구현하면서 며칠동안 강의도 찾아보고 언리얼 공식 문서도 찾아보면서 다른 파일을 cast하여 참조하는 작업에 많이 익숙해졌다. 한국말로 되어있는 강의가 별로 없는데다가 유튜브에서 찾은 외국 강의들도 각자 구현하는 방식이 모두 달라 결국 나 자신만의 세이브 로드 구현을 설계해야 했고 세이브 로드 시 자료들이 어떻게 저장되어야하고 불러와지는지를 알아보기 위해 매번 디버그로 한 노드씩 점검해가며 재밌게 공부를 할 수 있는 기회가 되었다. 

winapi를 공부할 때엔 비주얼 스튜디오로 하는 디버깅이 눈에 잘 안들어오고 힘들었는데 언리얼엔진5를 사용하면서 디버깅이 한눈에 들어오는 점이 정말 마음에 들었다. 그리고 유니티보단 적지만 winapi보다 훨씬 많은 정보를 찾을 수 있었다.

 

블루프린트를 사용하며 느낀 장점은 무엇보다 설계를 할 때 직관적으로 눈에 들어온다는 점이었다. 특히 이론으로만 공부하면 포인터처럼 헷갈리기 쉬운 개념들의 흐름을 눈으로 볼 수 있다는 점이 코딩 초보자의 입장에서는 매우 크게 와닿았다. 그리고 c++을 사용할 땐 자고 일어나면 전날 설계했던 코드들을 다시 읽어보고 머리속에 정리하는데 긴 시간을 사용했었지만 코멘트와 한눈에 들어오는 비주얼 덕분에 코드 정리에 큰 도움이 되었으며, 한칸 한칸 따라가며 디버깅 할 때 더 눈에 잘 익혀지는 점이 좋았다. 


블루프린트를 사용하면서 불편했던 점은 switch문이나 if문의 구현에서 조금 번거롭다는 점과 변수에 직접 개입하고 싶어도 변수로 승격하고 set을 이용하여야 설정을 할 수 있기 때문에 c++과 병행하여 설계하면 더 쉽고 빠르게 설계할 수 있을것이라 생각했다.