본문 바로가기

Unity Engine

유니티 엔진 JsonUtility 다루기 - JSON 읽기

728x90
728x90

이 포스트에서는 유니티 엔진에서 자체적으로 JSON을 다루게 해주는 JsonUtility를 통해 저장된 JSON 파일을 읽는 법을 배울 것이다.

 

읽는 사람이 JSON의 구조를 이해하고 있다고 가정하고 작성한다. JSON을 잘 모르면 모질라 재단에서 친절하게 설명하고 있으니 보고 오도록 하자. 자바스크립트도 어느 정도 공부하면 더욱 좋을 것이다.

 

유니티 엔진을 다루면서 특정 데이터를 보관할 일이 있다. 아이템의 능력치나 기타 유니티 내 스크립트에 하드 코딩하기 껄끄러운 대상은 보통 XML 또는 JSON으로 보관한다.

 

유니티 엔진에는 자체적으로 JsonUtility 모듈을 가지고 있어 JSON 포맷을 관리할 수 있게 해 준다. 지원하는 기능이 적다는 단점이 있지만 충분히 작은 프로젝트에서는 JsonUtility를 써도 충분하다.

JSON 파일 생성

유니티에서 파싱 할 json 파일을 하나 만들자. 바닐라 에디터에서는 JSON 포맷 파일을 생성할 수 없어 직접 파일 탐색기에서 만들어야 한다.

 

유니티에서 json 파일을 로드하려면 무조건 Resources 폴더 안에 있어야 한다. 대충 Resources 폴더 안에 JSON 폴더를 만들어 파일을 배치하면 될 것이다.

 

알아서 만들자

 

그리고 대충 json 객체의 내용물을 만들자.

 

 

이제 저 json 객체에는 3개의 프로퍼티가 들어있다. 이 데이터를 꺼내보도록 하겠다.

Serializable 클래스 생성

json 객체를 성공적으로 불러오기 위해선 객체를 래핑 할 클래스를 만들어야 한다. 예를 들어 위 객체를 꺼내기 위해선 다음과 같은 클래스 혹은 구조체가 필요하다.

참고로 json에서 데이터를 직렬화 시키고 싶으면 [System.Serializable]을 달아 직렬화가 가능함을 명심하자. 그리고 json 파일을 읽을 때 프로퍼티의 키와 변수 이름이 일치해야 함을 유의한다.

 

단순히 데이터만 쓸 거면 메모리 관리를 위해 구조체로 하도록 하자.

 

쉽게 설명하면 현재 stat.json에 키로 "hp", "atk", "def"가 있는데 값을 제대로 가져오려면 똑같이 클래스에 hp, atk, def라는 이름의 변수가 존재해야 한다. 물론 자료형도 일치해야 한다.

 

클래스 이름은 마음대로 지어도 된다.

JSON 파일 읽기

Resources.Load를 사용해서 json 파일을 TextAsset 객체로 가져올 수 있다.

 

var loadedJson = Resources.Load<TextAsset>("JSON/stat");

 

 

여기서 loadedJson이 null 아니면 올바르게 불러왔다는 뜻이므로 이를 stat 객체로 파싱 해보자.

 

파싱을 위해선 JsonUtility의 FromJson 메서드를 사용해야 한다. stat 객체를 불러오기 위해선 아래와 같이 할 수 있다.

 

stat myStat = JsonUtility.FromJson<stat>(loadedJson.ToString());

 

파싱이 잘 되었는지 출력해보자.

 

Debug.Log($"{myStat.hp}, {myStat.atk}, {myStat.def}");

 

 

json 파일에 넣은 값이 잘 나온다.

 

이런 식으로 데이터를 불러와서 활용하면 된다.

여러 객체를 감싸기

하지만 한 파일에 한 객체만 불러오자고 이걸 보러 온 것은 아닐 테고 아마도 대부분은 위의 예제처럼 단일 객체를 가져오는 게 아니라 아래 사진처럼 객체들이 들어있는 어레이를 가져오려는 경우가 많을 것이다.

이 json 파일에는 Body라는 키에 객체들을 담은 어레이가 있다.

 

안타깝게도 JsonUtility는 이렇게 객체 안에 다른 객체를 가진 배열처럼 2단 이상으로 구성되면 한 클래스로 가져오지 못한다. 이를 해결하기 위해 해당 json 파일에서 객체로 보이는 건 다 클래스로 감싸줄 필요가 있다.

[System.Serializable]
class AudioInfo : IComparable
{
    public string part, sourceObject, clip;
    public int order;
    public float afterDelay;

    public int CompareTo(object arg)
    {
        if (order < (arg as AudioInfo).order) return -1;
        else return 1;
    }
}

 

위 코드는 Body키의 value인 어레이에 존재하는 객체를 AudioInfo라는 이름의 클래스로 감싼 것이다.

 

참고로 CompareTo 직렬화를 하려는 용도로 있는 클래스도 인터페이스를 상속할 수 있으니 참고하자.

 

어레이의 원소로 있는 객체를 클래스로 만들었으니 저 어레이를 어떻게 표현할지 살펴보자.

 

이는 단순히 AudioInfo를 담는 List를 가진 클래스를 만들면 된다. 물론 위 예시에서 프로퍼티의 키가 "Body"이므로 리스트의 이름 역시 Body가 되어야 한다.

[System.Serializable]
class StoryData
{
    public List<AudioInfo> Body;
}

 

이렇게 2개의 클래스를 만들고 위 json 파일을 파싱 할 때 StoryData를 파싱 하도록 하면 나머지 객체들도 알아서 파싱 된다.

 

이 정도만 알아도 json 파일을 무리 없이 파싱 할 수 있을 것이다.

더 복잡한 경우

배열에 한 종류(형식)의 객체가 아니라 여러 개가 들어간다면 JSON Utility로 파싱 하는 것을 포기하고 다른 외부 라이브러리를 알아보도록 하자.

 

지금까지 JSON Utility로 json 파일을 읽는 방법을 알아보았다.

728x90
728x90