Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

Typing diary

Unity Serializable Dictionary (스크립트 직렬화) 본문

Unity

Unity Serializable Dictionary (스크립트 직렬화)

Jcon 2024. 9. 10. 00:13

직렬화 ( Serialize)

작렬화란 데이터의 구조나, 오브젝트의 상태를 저장하고 나중에 다시 재구성할 수 있는 포맷으로 변환하는 과정이다. 

상황에 따라 byte스트림이나 Json,XML과 같은 문자 포맷을 사용한다. 유니티에선 YAML언어를 사용하여 데이터를 저장하는데, .prefab이나 .scene파일을 텍스트 편집기로 열어보면 YAML형태로 데이터가 저장된 것을 볼 수 있다. 유니티는 YAML언어로 저장된 데이터를 읽어와 Inspector창에서 데이터를 편집할 수 있게 제공한다. 

 

[Serializable], [SerializeField]

데이터를 직렬화 하기 위해 명시하는 어트리뷰트이다. 

Serializable한 타입을 public이나, SerializeField로 선언해 주면 유니티에서 해당 데이터를 YAML로 변환하여 저장한다. 

여기서 Serializable한 타입은 기본 데이터 타입(int, float, string, bool ... ), 특정 Unity 내장 타입 (Vector2,3,4, Color, Matrix4x4...), 컨테이너 필드 (List<T>)등이 있다. 

 


SerializableDictionary

유니티를 사용하다 보면, Dictionary타입의 데이터를 Inspector창에서 수정하고 싶은 상황이 자주 발생한다. 하지만 C#에서 기본 제공하는 Dictionary는 Serializable타입이 아니기 때문에 직렬화가 불가능하다. 다행히 유니티에선 이런 상황에서 사용할 수 있는 여러 Serialize 커스텀 기능을 제공한다. 

 

Dictionary를 직렬화 하기 위해 유니티에서 기본으로 제공해 주는 Serializable 타입인 List를 사용할 것이다.

위 그림과 같이 직렬화시 List형식으로 저장하고, 역직렬화 시, Dictionary로 다시 재가공하여 사용하는 방식으로 구현할 생각이다.

 

 

[Serializable]
public class SerializableKeyValue<K,V>
{
    public K Key;
    public V Value;
}

일단 Key,Value를 묶어서 List로 저장하기 위해 SerializableKeyValue클래스를 정의한다.

재사용을 위해 제네릭 클래스로 선언하고, SerializableKeyValue도 당연히 직렬화 되어야 함으로 Serialiable 어트리뷰트를 적용한다.

 

 

그 다음 SerializableDictionary클래스를 선언한다. Dictionary 클래스에서 재공하는 함수를 그대로 사용하기 위해, Dictionary를 상속 받고, ISerializationCallbackReceiver인터페이스를 사용하여 직렬화, 역직렬화 로직을 작성한다. 

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

[Serializable]
public class SerializableKeyValue<K,V>  where K : class
{
    public K Key;
    public V Value;
}

[Serializable]
public class SerializableDictionary <K,V> : Dictionary<K,V>, ISerializationCallbackReceiver where K : class
{
    [SerializeField] private List<SerializableKeyValue<K, V>> _keyValueList;

    public void OnBeforeSerialize() 
    {
        if (this.Count < _keyValueList.Count)
        {
            return;
        }

        _keyValueList.Clear();
        
        foreach (var kv in this)
        {
            _keyValueList.Add(new SerializableKeyValue<K, V>()
            {
                Key = kv.Key,
                Value = kv.Value
            });
        }        
    }

    public void OnAfterDeserialize() 
    {
        this.Clear();
        foreach (var kv in _keyValueList)
        {
            if(!this.TryAdd(kv.Key, kv.Value))
            {
                Debug.LogError($"List has duplicate Key");
            }
        }
    }
}

 

이렇게 코드를 작성하고 테스트한 결과, Serialize(Dictionary -> List), Deserialize (List -> Dictionary) 모두 잘 작동하는 것을 확인했다. 

 

 

이렇게 저장된 프리팹 파일을 텍스트 편집기로 열어보면, 

 

 

List와 동일하게 직렬화 된것을 볼 수 있다.

'Unity' 카테고리의 다른 글

Unity Addressables localhost로 Remote번들 테스트하기  (0) 2024.07.29