오늘은 팀프로젝트에서 만든 저장 및 불러오기 시스템을 설명하며,
나중에 또 좋은 틀로 사용할 수 있을것 같아서 작성하게 되었다.
3가지 슬롯을 만들고 저장 및 불러오기 그리고 저장 된 파일이 없을면 새로운 시작 을 표기하고 싶었고
저장된 슬롯의 파일을 지우는 기능도 만들고싶었다.(욕심이 그득)
우선 코드를 보여주고 설명을 하겠다.
public class SaveSlotUI : MonoBehaviour
{
public Button[] slotButtons;
public TextMeshProUGUI[] slotTexts;
public SaveLoadManager saveLoadManager;
public TMP_InputField nameInputField;
public GameObject nameEntryPanel;
private int selectedSlot = -1;
private void Start()
{
LoadSlotInfo();
}
private void LoadSlotInfo()
{
for (int i = 0; i < slotButtons.Length; i++)
{
var saveData = saveLoadManager.LoadGame(i);
slotTexts[i].text = saveData != null ? $"이름 : {saveData.playerName} \n 레벨 : {saveData.level}" : "새로운 시작";
}
}
public void SelectSlot(int slot)
{
AudioManager.Instance.PlaySFX(AudioManager.Sfx.Button);
selectedSlot = slot;
var saveData = saveLoadManager.LoadGame(slot);
if (saveData != null)
{
saveLoadManager.SetCurrentSlotIndex(slot);
StartSavedGame(saveData);
}
else
{
nameEntryPanel.SetActive(true);
saveLoadManager.SetCurrentSlotIndex(slot);
}
}
public void StartNewGame()
{
AudioManager.Instance.PlaySFX(AudioManager.Sfx.Button);
if (selectedSlot < 0) return;
string playerName = nameInputField.text;
if (string.IsNullOrEmpty(playerName)) return;
SaveData newSaveData = new SaveData
{
playerName = playerName,
level = 1,
};
saveLoadManager.SaveGame(newSaveData, selectedSlot);
nameEntryPanel.SetActive(false);
LoadSlotInfo();
LevelController.Instance.currentLevel = 1;
SceneManager.LoadScene("Level1");
PuzzleManager.Instance.InitializePuzzle();
}
public void DeleteSlot(int slot)
{
AudioManager.Instance.PlaySFX(AudioManager.Sfx.Button);
saveLoadManager.DeleteGame(slot);
LoadSlotInfo();
}
private void StartSavedGame(SaveData saveData)
{
LevelController.Instance.currentLevel = saveData.level;
SceneManager.LoadScene($"Level{saveData.level}");
PuzzleManager.Instance.InitializePuzzle();
}
}
이 SaveSlotUI의 역할은 플레이어가 게임을 저장하거나 불러오는 세이브 슬롯 UI를 관리한다.
주요메서드는 아래와 같다.
LoadSlotInfo : 각 슬롯의 저장된 데이터를 불러와 UI에 표시하고, 저장된 정보가 없으면 "새로운 게임"을 표시한다.
SelectSlot : 슬롯을 선택했을 떄 햇당 슬롯에 데이터가 있으면 게임을 시작, 아니면 이름 입력 패널을 표시한다.
StartNewGame : 새로운 게임을 시작할때 호출되고 초기데이터를 저장한다.
DeleteSlot : 해당 슬롯의 데이터를 삭제한다
StartSavedGame : 저장된 게임을 불러와서 해당 레벨로 시작한다.
다음은 세이브 로드 매니저이다.
using System.IO;
using UnityEngine;
public class SaveLoadManager : Singleton<SaveLoadManager>
{
private string saveFolderPath = @"C:\PuzzleHorror\Saves";
public int currentSlotIndex = 0;
private void Start()
{
if (!Directory.Exists(saveFolderPath))
{
Directory.CreateDirectory(saveFolderPath);
}
}
public void SaveGame(SaveData data, int slotIndex)
{
string filePath = Path.Combine(saveFolderPath, $"save_slot_{slotIndex}.json");
string jsonData = JsonUtility.ToJson(data, true);
File.WriteAllText(filePath, jsonData);
}
public void SaveCurrentProgress(int level)
{
SaveData currentData = LoadGame(currentSlotIndex);
string playerName = currentData.playerName;
SaveData data = new SaveData
{
playerName = playerName,
level = level
};
SaveGame(data, currentSlotIndex);
}
public SaveData LoadGame(int slotIndex)
{
string filePath = Path.Combine(saveFolderPath, $"save_slot_{slotIndex}.json");
if (File.Exists(filePath))
{
string jsonData = File.ReadAllText(filePath);
return JsonUtility.FromJson<SaveData>(jsonData);
}
return null;
}
public void DeleteGame(int slotIndex)
{
string filePath = Path.Combine(saveFolderPath, $"save_slot_{slotIndex}.json");
if (File.Exists(filePath))
{
File.Delete(filePath);
}
}
public void SetCurrentSlotIndex(int slotIndex)
{
currentSlotIndex = slotIndex;
}
}
오히려 UI보다 간단해보이는 진짜 세이브 로드를 담당하는 세이브 로드 매니저이다.
위와 동일하게 주요 메서드만 설명하겠다
SaveGame : 특정 슬롯의 SaveData를 JSON 파일로 저장합니다.
SaveCurrentProgress : 현재 슬롯에 진행 중인 레벨 정보를 업데이트합니다.
LoadGame : 특정 슬롯에서 JSON 파일을 읽어 SaveData 객체로 변환하여 불러옵니다.
DeleteGame : 특정 슬롯의 저장 파일을 삭제합니다.
SetCurrentSlotIndex : 현재 선택된 슬롯의 인덱스를 설정합니다. (슬롯이 3개라서 UI에서 받아옴)
그리고 SaveData는 이렇게 간단하게 구성되어있습니다.
[Serializable]
public class SaveData
{
public string playerName;
public int level;
}
[Serializable]의 특성을 이용하여, JSON형태로 직렬화 및 역직렬화가 가능합니다.