본문 바로가기
유니티

Day 38 - SaveManager.cs 생성(정보 저장)

by shin0707 2024. 6. 11.
728x90

  • 주제

>> 게임 정보(인벤토리, 컨디션)를 Jason으로 저장하고 불러오는 기능을 담당하는 클래스 생성

>> 싱글톤 패턴으로 관리하여 확장성 높이기

>> 인벤토리 데이터를 관리하는 스크립트에 저장 관련 메서드 추가


  • 공부내용

1. 저장기능 클래스 생성(SaveManager.cs)

-게임 정보를 쉽게 저장하여 씬 전환이나 게임 종료 후 다시 시작해도 게임 정보를 불러올 수 있도록 확장

 

명사형 한글 주석

-저장경로: savePath

Application.persistentDataPath는 각 플랫폼에 맞는 저장 경로를 반환

 

-저장 데이터: SaveData

JsonUtility.ToJson 메서드를 사용하여 객체를 JSON 문자열로 변환하고, 이를 파일에 저장

 

-데이터 불러오기: LoadData

파일이 존재하면 내용을 읽어 JsonUtility.FromJson 메서드를 통해 객체로 변환

using System.IO;
using UnityEngine; 

// 저장 관리 클래스
public class SaveManager : MonoBehaviour
{
    // 싱글톤 인스턴스
    public static SaveManager Instance { get; private set; }

    // 저장 경로
    private string savePath;

    private void Awake()
    {
        // 싱글톤 패턴 설정
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject); // 씬이 전환되도 파괴되지 않게 설정
            savePath = Path.Combine(Application.persistentDataPath, "saveData.json"); // 저장 경로 설정
        }
        else
        {
            Destroy(gameObject); // 이미 인스턴스가 있으면 파괴
        }
    }

    // 데이터 저장 메서드
    public void SaveData(SaveData data)
    {
        string json = JsonUtility.ToJson(data, true); // 데이터를 JSON 형식으로 변환
        File.WriteAllText(savePath, json); // 파일에 JSON 데이터 저장
    }

    // 데이터 불러오기 메서드
    public SaveData LoadData()
    {
        if (File.Exists(savePath))
        {
            string json = File.ReadAllText(savePath); // 파일에서 JSON 데이터 읽기
            return JsonUtility.FromJson<SaveData>(json); // JSON 데이터를 SaveData 객체로 변환
        }
        return null; // 파일이 없으면 null 반환
    }
}

// 저장 데이터 클래스
[System.Serializable]
public class SaveData
{
    public List<ItemData> items; // 아이템 목록
    public List<int> quantities; // 아이템 수량 목록
}

 

2. UIInventory.cs (저장메서드 추가)

 

- Awake 메서드: 초기 설정을 담당합니다. 슬롯들을 찾고, 버튼들을 초기화합니다.

- Start 메서드: 버튼 클릭 이벤트를 설정하고, 슬롯을 초기화하며, 인벤토리 데이터를 불러옵니다.

- OnApplicationQuit 및 OnDestroy 메서드: 게임 종료 또는 씬 전환 시 인벤토리 데이터를 저장합니다.

- SaveInventory 메서드: 현재 인벤토리 데이터를 SaveData 객체에 저장하고, SaveManager를 통해 파일에 저장합니다.

- LoadInventory 메서드: SaveManager를 통해 파일에서 데이터를 불러와 슬롯에 설정합니다.

 

using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class UIInventory : MonoBehaviour
{
    // 설명 인덱스 열거형
    private enum eDescriptionIndex
    {
        ITEM_NAME, // 아이템 이름
        ITEM_DESCRIPTION, // 아이템 설명
        STAT_NAME, // 스탯 이름
        STAT_VALUE // 스탯 값
    }

    // 버튼 인덱스 열거형
    private enum eBtnIndex
    {
        USE_BTN, // 사용 버튼
        DROP_BTN, // 버리기 버튼
        EQUIP_BTN, // 장착 버튼
        UNEQUIP_BTN, // 장착 해제 버튼
        INSTALL_BTN // 설치 버튼
    }

    public event Action InventoryRefresh; // 인벤토리 갱신 이벤트

    [Header("Inventory")]
    private Transform holdings; // 아이템 슬롯들
    public List<TextMeshProUGUI> selectedDescriptions; // 선택된 아이템 설명들
    public List<GameObject> invenBtns = new List<GameObject>(); // 인벤토리 버튼들
    public ItemSlot[] slots { get; private set; } // 아이템 슬롯 배열
    private ItemSlot selectedSlot; // 선택된 슬롯

    private PlayerCondition condition; // 플레이어 상태
    private Transform dropPosition; // 아이템 버리는 위치

    private void Awake()
    {
        holdings = transform.Find("Holdings"); // Holdings 오브젝트 찾기

        foreach (Transform transform in transform.Find("ItemInfo"))
        {
            if (transform.TryGetComponent(out TextMeshProUGUI component))
                selectedDescriptions.Add(component); // ItemInfo에서 TextMeshProUGUI 컴포넌트 찾기
        }

        foreach (Transform transform in transform.Find("InvenBtns"))
        {
            invenBtns.Add(transform.gameObject); // InvenBtns에서 버튼 오브젝트들 찾기
        }
    }

    private void Start()
    {
        invenBtns[(int)eBtnIndex.USE_BTN].GetComponent<Button>().onClick.AddListener(OnUseBtn);
        invenBtns[(int)eBtnIndex.DROP_BTN].GetComponent<Button>().onClick.AddListener(OnDropBtn);
        invenBtns[(int)eBtnIndex.EQUIP_BTN].GetComponent<Button>().onClick.AddListener(OnEquipBtn);
        invenBtns[(int)eBtnIndex.UNEQUIP_BTN].GetComponent<Button>().onClick.AddListener(OnUnequipBtn);
        invenBtns[(int)eBtnIndex.INSTALL_BTN].GetComponent<Button>().onClick.AddListener(OnInstallBtn);

        // 슬롯 초기화
        slots = new ItemSlot[holdings.childCount];

        for (int i = 0; i < slots.Length; i++)
        {
            slots[i] = holdings.GetChild(i).GetComponent<ItemSlot>();
            slots[i].inventory = this;
            slots[i].slotIndex = i;
            slots[i].Clear();
        }

        CharacterManager.Instance.Player.addItem += AddItem;
        condition = CharacterManager.Instance.Player.condition;
        dropPosition = CharacterManager.Instance.Player.dropPosition;

        ClearSelectedItemWindow();
        UpdateUI();

        // 인벤토리 불러오기
        LoadInventory();
    }

    private void OnApplicationQuit()
    {
        SaveInventory(); // 게임 종료 시 인벤토리 저장
    }

    private void OnDestroy()
    {
        SaveInventory(); // 씬 전환 시 인벤토리 저장
    }

    // 인벤토리 저장 메서드
    public void SaveInventory()
    {
        SaveData saveData = new SaveData();
        saveData.items = new List<ItemData>();
        saveData.quantities = new List<int>();

        foreach (var slot in slots)
        {
            if (slot.item != null)
            {
                saveData.items.Add(slot.item); // 아이템 데이터 추가
                saveData.quantities.Add(slot.quantity); // 아이템 수량 추가
            }
        }

        SaveManager.Instance.SaveData(saveData); // 저장 관리 클래스에 데이터 저장 요청
    }

    // 인벤토리 불러오기 메서드
    public void LoadInventory()
    {
        SaveData saveData = SaveManager.Instance.LoadData(); // 저장 관리 클래스에서 데이터 불러오기 요청

        if (saveData != null)
        {
            for (int i = 0; i < saveData.items.Count; i++)
            {
                ItemSlot emptySlot = GetEmptySlot(); // 빈 슬롯 찾기
                if (emptySlot != null)
                {
                    emptySlot.item = saveData.items[i]; // 아이템 데이터 설정
                    emptySlot.quantity = saveData.quantities[i]; // 아이템 수량 설정
                }
            }

            UpdateUI(); // UI 업데이트
        }
    }

.....

    public void UpdateUI()
    {
        for (int i = 0; i < slots.Length; i++)
        {
            if (slots[i].item != null)
            {
                slots[i].Set();
            }
            else
            {
                slots[i].Clear();
            }
        }

        InventoryRefresh?.Invoke();
    }
    
.....

 

 

728x90
반응형