Data Manager

선비Sunbei·2023년 1월 26일
0

Unity

목록 보기
16/18
post-thumbnail
post-custom-banner

유니티엔진에서 하드코딩을 통해서 데이터를 저장할 수 있다. 하지만 이는 매우 비효율적이다. 일단 유지보수 측면에서 어려우며, 프로그래머가 아니면 작업하기 힘들다. 그렇기 때문이 이를 해결하고자 우리는 json 형태의 파일로 데이터를 저장해서 불러올 것이다.

여기서 json에 저장되는 내용은 캐릭터에 대한 내용일 수도, 몬스터에 대한 기본적인 정보일 수도 있다.

json은 다음과 같이 저장되어 있다.

{
  "field" : [
    {
    	"data1" : "010111"
      	"data2" : "011100"
    },
    {
     	"data1" : "010011"
      	"data2" : "000111"
    }
  ]
}

JSON에서는 []는 배열을 의미하여서 데이터 값의 집합으로 저장하고, {}의 경우 구조체 혹은 Map이라고 보면된다. 주의할 점은 int형이든 string형이든 ""으로 나타낸다. 후에 자동으로 형 변환을 해준다.

C#에서는 직렬화를 제공해준다. 직렬화는 간단하게 이야기하면 메모리에 할당된 클래스의 객체를 바이너리화 해서 저장하는 것을 얘기한다. 반대로 역직렬화는 디스크에 저장한 데이터를 읽어내는 것을 얘기한다.

C#에서 객체를 직렬화 할 수 있는 간단한 방법을 제공한다. 그것은 [Serializable] 어트리뷰트를 클래스 선언부 앞에 붙여주면 이 클래스는 메모리나 디스크에 저장이 가능하다.

하지만 C#에서의 직렬화는 바이너리 직렬화로 이진값이 저장된다. 이렇게 되면 개발자가 아닌 사람은 수정하려면 외부 프로그램이 한번 더 필요하다는 단점이 있기 때문에 Unity의 JsonUtility를 이용하여 Json 직렬화 혹은 역직렬화를 진행한다.

다음과 같이 Resources에 Data 폴더를 만들어서 json을 만들어주겠다.

{
  "stats": [
    {
      "level": "1",
      "hp": "10",
      "mp": "20"
    },
    {
      "level": "2",
      "hp": "20",
      "mp": "30"
    },
    {
      "level": "3",
      "hp": "30",
      "mp": "40"
    }
  ]
}

내용은 다음과 같다.

using System.Collections.Generic;
using UnityEngine;
using System;

public class DataManager 
{
    public interface ILoader<Key, Value> {
        Dictionary<Key, Value> MakeDictionary();
    }

    Loader LoadJson<Loader,Key,Value>(string path) where Loader : ILoader<Key, Value>
    {
        TextAsset textAsset = Manager.Instance.mResourceManager.Load<TextAsset>(path);
        return JsonUtility.FromJson<Loader>(textAsset.text);
    }
   
    [Serializable]
    public class statClass
    {
        public int level;
        public int hp;
        public int mp;
    }

    [Serializable]
    public class statsClass : ILoader<int, statClass>
    {
        public List<statClass> stats;

        public Dictionary<int, statClass> MakeDictionary()
        {
            Dictionary<int, statClass> dic = new Dictionary<int, statClass>();
            foreach(statClass stat in stats)
            {
                dic.Add(stat.level, stat);
            }
            return dic;
        }
    }

    Dictionary<int, statClass> statDic;

    public void Init()
    {
        statDic = LoadJson<statsClass,int,statClass>("Data/Characterinfo").MakeDictionary();


        TextAsset textAsset = Manager.Instance.mResourceManager.Load<TextAsset>("Data/Characterinfo");
        Debug.Log(textAsset.text);

        statClass st;
        statDic.TryGetValue(1, out st);
        Debug.Log("level : " + st.level + " , hp : " + st.hp + " , mp :" + st.mp);
    }
}

주의할점은 다음과 같다.
1. 직렬화 혹은 역직렬화 할 [Serializable] 어트리뷰트를 붙여야 한다.
2. public을 꼭 붙여야 한다.
3. 변수명은 json의 Key값과 반드시 같아야 한다.

이제 풀어서 설명은 해보겠다.
TextAsset은 text 값을 얻어오기 위한 UnityEngine.Object이다.
이러한 TextAsset의 text를 JsonUtility.FromJson<역직렬화할 class명>(text)를 통해서 클래스에 역직렬화를 해줬다.

역직렬화 할 클래스는 다음과 같은 특징이 있다.
1. public으로 되어있다. (private이면 못불러옴)
2. json의 []의 경우 List로 혹은 배열로 받아야 한다. (이때 Key값의 이름과 같아야 한다.)
3. json의 {}의 Key 값들은 변수의 이름과 같아야 한다.
4. [Serializable] 어트리뷰트를 갖고 있다.

Dictionary로 한 이유는 json을 역직렬화하려면 List 혹은 Value로만 받을 수 있기 때문에 나중에 손 쉽게 데이터를 접근하기 위해서 Dictionary 형태로 다시 만들어서 관리하려고 하기 때문이다.

직렬화를 하는 방법은 다음과 같다.

    public void Init()
    {
        statDic = LoadJson<statsClass,int,statClass>("Data/Characterinfo").MakeDictionary();

        statClass st = new statClass();
        st.level = 4;
        st.hp = 50;
        st.mp = 50;
        Debug.Log(JsonUtility.ToJson(st));
    }

JsonUtility.ToJson()을 사용하면 되고 string을 리턴하게 된다.
이를 파일 형태로 저장하면 된다.

    public void Init()
    {
        statDic = LoadJson<statsClass,int,statClass>("Data/Characterinfo").MakeDictionary();

        statClass st = new statClass();
        st.level = 4;
        st.hp = 50;
        st.mp = 50;
        string customJsonString = JsonUtility.ToJson(st);

        st.level = 20;
        st.hp = 2000;
        st.mp = 4000;

        JsonUtility.FromJsonOverwrite(customJsonString, st);
        Debug.Log("level : " + st.level + " , hp : " + st.hp + " , mp :" + st.mp);
    }

추가적으로 json으로 불러들여온 값을 일일히 넣어주는 작업을 해주지 않아도 된다.
다음과 같이 JsonUtility.FromJsonOverwrite(string,object)를 이용하면 저장해놓은 값들을 손 쉽게 object에 직렬화해서 덮어씌울 수 있다.

참고로 [NonSerialized]를 어트리뷰트로 변수 위에 씌울 시 해당 값은 직렬화가 되지않는다.

post-custom-banner

0개의 댓글