오늘은 만들어둔 시스템의 데이터를 저장하고 불러오는 기능을 구현해보자.
우선 Save를 관리해줄 SaveManager를 만들어주자. 경로는 기본경로로 해주고 저장방식은 Json으로 저장해주도록 하자.
SaveManager.cs
public class SaveManager
{
public void Init()
{
// 경로 설정
_defaultPath = Path.Combine(Application.persistentDataPath, "saveData.json");
// 디렉터리 확인 및 생성
string directoryPath = Path.GetDirectoryName(_defaultPath);
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
Debug.Log($"Save File Path Initialized: {_defaultPath}");
}
}
그리고 지금까지 만들어둔 시스템에서 저장할 부분을 직렬화방식으로 저장하기 위해 SaveData를 따로 만들어주자. 저장해야할 부분은 Inventory,Quest,Player 데이터를 저장하면 된다.
SaveData.cs
using System;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SaveData
{
public List<SerializedItemSlot> inventoryData; // 인벤토리 데이터
public PlayerData playerData; // 플레이어 데이터
public List<SerializedQuestData> questData; // 퀘스트 데이터
}
[System.Serializable]
public class PlayerData
{
public Vector3 position; // 플레이어 위치
public Vector3 rotation; // 플레이어 방향
public float health; // 플레이어 체력
}
[System.Serializable]
public class SerializedItemSlot
{
public int itemID; // 아이템 ID
public int quantity; // 아이템 개수
}
[System.Serializable]
public class SerializedQuestData
{
public int questID; // 퀘스트 ID
public string questState; // 퀘스트 상태
}
이렇게 하고 저장하는 부분을 구현해볼텐데 저장은 직렬화로 구현된 부분을 각 객체의 함수로 추가하고 마지막에 SaveManager에서 Json으로 저장하도록하자
Player.cs
// 저장
public void SavePlayer(ref SaveData saveData)
{
saveData.playerData = new PlayerData
{
position = transform.position,
rotation = transform.eulerAngles,
health = currentHealth
};
}
QuestManager.cs
public void SaveQuests(ref SaveData saveData)
{
List<SerializedQuestData> serializedQuests = new List<SerializedQuestData>();
foreach (var quest in Quests.Values)
{
serializedQuests.Add(new SerializedQuestData
{
questID = quest.questId,
questState = quest.questState.ToString()
});
}
saveData.questData = serializedQuests;
}
InventoryManager.cs
// 저장
public void SaveInventory(ref SaveData saveData)
{
List<SerializedItemSlot> serializedInventory = new List<SerializedItemSlot>();
foreach (var slot in inventory)
{
serializedInventory.Add(new SerializedItemSlot
{
itemID = slot.itemData.itemID,
quantity = slot.quantity
});
}
saveData.inventoryData = serializedInventory;
}
SaveManager.cs
public void SaveData()
{
SaveData saveData = new SaveData();
Managers.Inventory.SaveInventory(ref saveData);
Managers.Game.GetPlayer().GetComponent<Player>().SavePlayer(ref saveData);
Managers.Quest.SaveQuests(ref saveData);
string json = JsonUtility.ToJson(saveData, true);
File.WriteAllText(_defaultPath, json);
Debug.Log($"게임 데이터가 저장되었습니다: {_defaultPath}");
}
이렇게 만들고 게임 데이터를 가져오는 기능을 만들어주자. 이때 만약 저장데이터가 없다면 기본 데이터를 저장해주고
다른 시스템을 초기화해주는 기능도 넣어주도록 하자.
SaveManager.cs
public void LoadData()
{
if (!File.Exists(_defaultPath))
{
Debug.LogWarning("저장된 데이터가 없습니다. 초기 데이터를 생성합니다.");
// 초기 데이터를 생성
CreateInitialData();
SaveData(); // 초기 데이터를 저장
return;
}
string json = File.ReadAllText(_defaultPath);
SaveData saveData = JsonUtility.FromJson<SaveData>(json);
SpawnPlayer();
Managers.Quest.Init();
Managers.Inventory.LoadInventory(saveData);
Managers.Game.GetPlayer().GetComponent<Player>().LoadPlayer(saveData);
Managers.Quest.LoadQuestsFromSaveFile(saveData);
Debug.Log("게임 데이터가 불러와졌습니다.");
}
private void CreateInitialData()
{
SpawnPlayer();
// 인벤토리 초기화
Managers.Inventory.Init();
//Managers.Inventory.AddItem(Resources.Load<ItemData>("Items/Potion"), 5); // 기본 아이템 추가
//Managers.Inventory.AddItem(Resources.Load<ItemData>("Items/Sword"), 1); // 기본 무기 추가
// 플레이어 초기화
var player = Managers.Game.GetPlayer().GetComponent<Player>();
player.transform.position = Vector3.zero; // 기본 위치
player.CurrentHealth = 100f; // 기본 체력
player.index = 0; // 초기 퀘스트 인덱스
// 플레이어 정보 출력
Debug.Log("=== 플레이어 초기화 ===");
Debug.Log($"위치: {player.GetComponent<Player>().transform.position}");
Debug.Log($"체력: {player.GetComponent<Player>().CurrentHealth}");
Debug.Log($"퀘스트 진행 상태: {player.GetComponent<Player>().index}");
// 퀘스트 초기화
Managers.Quest.Init();
}
public void SpawnPlayer()
{
GameObject player = Managers.Game.Spawn(Define.WorldObject.Player, "Player");
CinemachineVirtualCamera virtualCamera = GameObject.FindObjectOfType<CinemachineVirtualCamera>();
virtualCamera.Follow = player.transform; // virtual camera의 Follow에 플레이어 등록
}
Player.cs
// 불러오기
public void LoadPlayer(SaveData saveData)
{
if (saveData.playerData == null) return;
transform.position = saveData.playerData.position;
transform.eulerAngles = saveData.playerData.rotation;
currentHealth = saveData.playerData.health;
}
QuestManager.cs
public class QuestManager
{
[SerializeField] private Dictionary<int, QuestData> Quests;
public void Init()
{
LoadQuestsFromResources();
InitializeQuest();
}
// Resources 폴더에서 모든 ScriptableObject를 로드하고 Dictionary로 초기화
private void LoadQuestsFromResources()
{
QuestData[] loadedQuests = Resources.LoadAll<QuestData>("Quest");
Quests = new Dictionary<int, QuestData>();
if (loadedQuests.Length == 0)
{
Debug.LogError("Resources/Quest 폴더에 퀘스트 데이터가 없습니다.");
return;
}
foreach (QuestData questData in loadedQuests)
{
if (!Quests.ContainsKey(questData.questId))
{
Quests.Add(questData.questId, questData);
Debug.Log($"퀘스트 Id '{questData.questId}' 인 '{questData.questName}'가 추가되었습니다.");
}
else
{
Debug.LogWarning($"중복된 questId({questData.questId})가 발견되었습니다. QuestName: {questData.questName}");
}
}
Debug.Log($"{Quests.Count}개의 퀘스트가 로드되었습니다.");
}
// Dictionary를 사용하여 퀘스트를 초기화
private void InitializeQuest()
{
if (Quests == null || Quests.Count == 0)
{
Debug.LogError("Quests가 null이거나 비어 있습니다. LoadQuestsFromResources를 확인하세요.");
return;
}
foreach (var questData in Quests.Values)
{
if (questData.QuestIndex >= Managers.Game.GetPlayer().GetComponent<Player>().index &&
questData.questState == QuestState.REQUIREMENTS_NOT_MET)
{
// 진행 가능한 상태로 변경
questData.questState = QuestState.CAN_START;
Debug.Log($"퀘스트 Id '{questData.questId}' 인 '{questData.questName}'가 CAN_START로 초기화되었습니다.");
}
}
}
public void LoadQuestsFromSaveFile(SaveData saveData)
{
if (saveData.questData == null) return;
Quests.Clear();
foreach (var serializedQuest in saveData.questData)
{
QuestData quest = FindQuestByID(serializedQuest.questID);
if (quest != null)
{
quest.questState = Enum.Parse<QuestState>(serializedQuest.questState);
Quests.Add(quest.questId, quest);
}
}
}
}
InventoryManager.cs
// 불러오기
public void LoadInventory(SaveData saveData)
{
if (saveData.inventoryData == null) return;
inventory.Clear();
foreach (var serializedSlot in saveData.inventoryData)
{
// 저장된 itemID를 통해 ItemData 불러오기
ItemData itemData = FindItemDataByID(serializedSlot.itemID);
if (itemData != null)
{
// 인벤토리에 새로운 ItemSlot 추가
inventory.Add(new ItemSlot { itemData = itemData, quantity = serializedSlot.quantity });
}
else
{
Debug.LogWarning($"ItemData를 찾을 수 없습니다: ID {serializedSlot.itemID}");
}
}
}
이렇게 해주고 테스트해보면 정상적으로 작동하는것을 볼 수 있다.
'게임공부 > Unity' 카테고리의 다른 글
[C#][Unity][나만의 탑뷰 게임 만들기]7. 인벤토리 시스템 만들기2 (0) | 2025.01.02 |
---|---|
[C#][Unity][나만의 탑뷰 게임 만들기]6. 인벤토리 시스템 만들기 (2) | 2024.12.28 |
[C#][Unity][나만의 탑뷰 게임 만들기]4. 아이템 시스템 만들기 (0) | 2024.12.18 |
[C#][Unity][나만의 탑뷰 게임 만들기]3. 퀘스트시스템 만들기-2 (1) | 2024.11.28 |
[C#][Unity][나만의 탑뷰 게임 만들기]3. 퀘스트시스템 만들기-1 (1) | 2024.11.25 |