상세 컨텐츠

본문 제목

1104 TIL - 데이터 저장

카테고리 없음

by lucar 2024. 11. 4. 22:47

본문

데이터 저장은 여러가지 방법이 있는데

 

PlayerPrefs, CSV, XML, JSON, SO 등 의 방법이 있다.

 

우선 CSV의 경우 엑셀에서 보기 쉽게 정리 할 수 있는 장점이 있지만

생성된 파일을 직접 보고 한 눈에 알아보기에는 큰 어려움이 있다.

 

대충 이런 엑셀파일을 작성 한 후

CSV파일로 다운로드 받자.

그리고 메모장으로 열어보면

 

진짜 복잡하게도 나오는데

하여튼 이것을 잘 잘라서 불러와보자.

 

우선 한 열은 \n으로 구분되며

각 행은 ,로 구분된다.

 

public class Dialogue : MonoBehaviour
{
    Dictionary<int, Item> ItemData = new Dictionary<int, Item>();
    string[] rowData;
    string[,] columnData;

    private void Start()
    {
        TextAsset csvData = Resources.Load<TextAsset>("./Data/CSV/CSVData");
        var data = csvData.text.TrimEnd();

        Deserialization(data);
    }

    public void Deserialization(string originData)
    {
        rowData = originData.Split('\n');
        for (int i = 1; i < rowData.Length; i++)
        {
            var data = rowData[i].Split(',');
            ItemData[int.Parse(data[0])] = new Item()
            {
                Name = data[1],
                Description = data[2],
                Price = data[3],
                ItemType = data[4],
                ...
            }
        }
        
        
    }
}

역 직렬화 코드를 짜주고

 

TextAsset 형식으로 불러온 후 TrimEnd()메서드를 이용해 맨 마지막 줄의 모든 여백을 제거한다.

 

다음은 XML 이다.

 

XML은 루트 노드, 자식 노드, 데이터 노드 순으로 나눠져 있는데

파일을 열어보면

<?xml version="1.0" encoding="UTF-8"?>
<GameData> //루트 노드
    <PlayerData> //자식 노드
    	<NickName>aa</NickName>
        <lv>10</lv>
        <hp>100</hp>
    </PlayerData>
</GameData>

대충 이런 식으로 저장이 되어있다.

 

보기에는 어디에 무슨 값이 있는지 CSV에 비해 상대적으로 읽기 편한 장점과

 

전혀 편하지 않은 작성 방법이 특징이다.

void CreateXML(Player p)
{
    XmlDocument xmlDoc = new XmlDocument();

    //xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration());

    // 루트 노드
    XmlNode root = xmlDoc.CreateNode(XmlNodeType.Element, "GameData", string.Empty);
    xmlDoc.AppendChild(root);

    // 자식 노드
    XmlNode child = xmlDoc.CreateNode(XmlNodeType.Element, "PlayerData", string.Empty);
    root.AppendChild(child);

    XmlElement nickname = xmlDoc.CreateElement("nickname");
    nickname.InnerText = p.nickname;
    child.AppendChild(nickname);

    XmlElement lv = xmlDoc.CreateElement("lv");
    lv.InnerText = p.lv.ToString();
    child.AppendChild(lv);

    XmlElement hp = xmlDoc.CreateElement("hp");
    hp.InnerText = p.hp.ToString();
    child.AppendChild(hp);

    xmlDoc.Save("./Assets/Resources/GameDatas.xml");

    AssetDatabase.Refresh(); // 에디터에서만 써야함.
}

단 3개의 값을 저장하기 위해 위와 같은 노력을 곁들여야 한다.

 

불러올 때도

void LoadXML()
{
    var t = Resources.Load<TextAsset>("GameDatas");

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(t.text);

    XmlNodeList nodes = xmlDoc.SelectNodes("GameData/PlayerData");

    XmlNode playerData = nodes[0];

    player.nickname = playerData.SelectSingleNode("nickname").InnerText;
    player.lv = int.Parse(playerData.SelectSingleNode("lv").InnerText);
    player.hp = float.Parse(playerData.SelectSingleNode("hp").InnerText);
}

이렇게 작성되는데

한 번 작성하고 나면 데이터를 저장하고 불러오는데 편리하지만

한 번 작성하기가 힘들다.

 

다음은 Json인데 Json중에서도 유니티에서 지원하는 JsonUtillity를 살펴보자

유니티 내부에서 실행 시 실행속도가 0에 가까운 속도를 지원한다고 한다.

 

중요한건 일반적인 데이터가 아닌

직렬화가 가능한 상태여야만 지원하고

이외에는 오딘이라는 에셋스토어에서 유료로 구매하는 에셋이 필요하다.

자세한 내용은 아래 링크 참조

https://docs.unity3d.com/kr/2019.4/Manual/JSONSerialization.html

 

JSON 직렬화 - Unity 매뉴얼

JsonUtility 클래스를 사용하여 Unity 오브젝트를 JSON 포맷으로 상호 전환할 수 있습니다. 예를 들어 JSON 직렬화를 사용하여 웹 서비스와 상호작용하거나, 데이터를 텍스트 기반 포맷으로 쉽게 패킹

docs.unity3d.com

 

public class Character : MonoBehaviour
{
    public UserData userData;

    public void Save()
    {
        var saveData = JsonUtility.ToJson(userData);

        Debug.Log(saveData);

        Debug.Log(Application.persistentDataPath + "/UserData.txt");
        File.WriteAllText(Application.persistentDataPath + "/UserData.txt", saveData);
    }

    public void Load()
    {
        string loadData = File.ReadAllText(Application.persistentDataPath + "/UserData.txt");

        userData = JsonUtility.FromJson<UserData>(loadData);
    }
}

살펴보면 저장 시에는 UserData형식을 그대로 string으로 변환하여 저장이 가능하고

불러 올때는 FromJson에 제너릭 타입을 입력하는 것으로 간단하게 로드가 가능하다.

 

대신 데이터는 완전히 직렬화 된 상태여야 하는데

[System.Serializable]
public class UserData
{
    public string nickname;
    public int lv;
    public float hp;

    public List<string> friends = new List<string>();
    public Inventory inven;
}

위 코드처럼 Inventory형식의 inven이라는 필드를 추가하더라도

 

[System.Serializable]
public class Inventory
{
    public int size;
}

해당 형식이 직렬화 되어있다면 문제 없이 저장 가능하다.

 

TTE