유니티 엔진

[유니티 2019.4.10f] 딕셔너리 인스펙터화

하루에 한번 방문하기 2021. 5. 28. 12:02

딕셔너리 인스펙터화 썸네일

이런 식으로 리스트 형태 Key Value를 보여주는 딕셔너리 자료형 인스펙터화 코드 입니다.

인스펙터에서 Key Value를 수정하면 딕셔너리도 수정됩니다. ( SyncDictionaryFromInspector() )

또 스크립트에서 딕셔너리에 Add나 Remove를 하면 인스펙터 내용이 수정됩니다.( SyncInspectorFromDictionary() )


전체 코드

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.Linq;

namespace CustomDic
{
    [System.Serializable]
    //[CanEditMultipleObjects]
    //[ExecuteInEditMode]
    public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
    {
        public List<TKey> g_InspectorKeys;
        public List<TValue> g_InspectorValues;

        public SerializableDictionary()
        {
            g_InspectorKeys = new List<TKey>();
            g_InspectorValues = new List<TValue>();
            SyncInspectorFromDictionary();
        }
        /// <summary>
        /// 새로운 KeyValuePair을 추가하며, 인스펙터도 업데이트
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public new void Add(TKey key, TValue value)
        {
            base.Add(key, value);
            SyncInspectorFromDictionary();
        }
        /// <summary>
        /// KeyValuePair을 삭제하며, 인스펙터도 업데이트
        /// </summary>
        /// <param name="key"></param>
        public new void Remove(TKey key)
        {
            base.Remove(key);
            SyncInspectorFromDictionary();
        }

        public void OnBeforeSerialize()
        {
        }
        /// <summary>
        /// 인스펙터를 딕셔너리로 초기화
        /// </summary>
        public void SyncInspectorFromDictionary()
        {
            //인스펙터 키 밸류 리스트 초기화
            g_InspectorKeys.Clear();
            g_InspectorValues.Clear();

            foreach (KeyValuePair<TKey, TValue> pair in this)
            {
                g_InspectorKeys.Add(pair.Key); g_InspectorValues.Add(pair.Value);
            }
        }

        /// <summary>
        /// 딕셔너리를 인스펙터로 초기화
        /// </summary>
        public void SyncDictionaryFromInspector()
        {
            //딕셔너리 키 밸류 리스트 초기화
            foreach (var key in Keys.ToList())
            {
                base.Remove(key);
            }

            for (int i = 0; i < g_InspectorKeys.Count; i++)
            {
                //중복된 키가 있다면 에러 출력
                if (this.ContainsKey(g_InspectorKeys[i]))
                {
                    Debug.LogError("중복된 키가 있습니다.");
                    break;
                }
                base.Add(g_InspectorKeys[i], g_InspectorValues[i]);
            }
        }

        public void OnAfterDeserialize()
        {
            Debug.Log(this + string.Format("인스펙터 키 수 : {0} 값 수 : {1}", g_InspectorKeys.Count, g_InspectorValues.Count));

            //인스펙터의 Key Value가 KeyValuePair 형태를 띌 경우
            if (g_InspectorKeys.Count == g_InspectorValues.Count)
            {
                SyncDictionaryFromInspector();
            }
        }
    }
}

사용 예제

public class EntityManager : MonoBehaviour
{
    [System.Serializable]
    public class SerializeDicEntity : CustomDic.SerializableDictionary<ENTITYTYPE, Entity>
    {

    }

    //Entitys 코드 분류에 따라, 엔티티 프리팹을 딕셔너리에 저장 
    public SerializeDicEntity g_EntityPrefabDictionary;

    public enum ENTITYTYPE
    {
        DUMMYMONSTER = 0, PLAYER = 1,
    }
}

클래스 상속과 직렬화 애트리뷰트를 쓴 후부터는

일반 딕셔너리와 같습니다. 단, Add와 Remove 메서드 호출 시마다 인스펙터와 싱크를 맞추기에 조금 더 무겁습니다.


이 분 코드에서 인스펙터를 수정하면 딕셔너리가 업데이트 되도록 수정했습니다.

https://redforce01.tistory.com/243

 

C# Unity - Serializable Dictionary

Serializable Dictionary Unity에서 TextMeshPro로 풀링 되어있는 HUD System을 만들다가 구조를 Dictionary로 잡게 되었는데 한가지 문제가 있었다. Unity 상에서 Dictionary 같은 경우엔 시리얼라이즈를 해도..

redforce01.tistory.com


참고 사이트 :

유니티 직렬화 콜백 공식 문서 https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html

 

Unity - Scripting API: ISerializationCallbackReceiver

Unity's serializer is able to serialize most datatypes, but not all of them. In these cases, there are two callbacks available for you to manually process these datatypes so that Unity can serialize and deserialise them. Care needs to be taken whilst withi

docs.unity3d.com

유니티 커스텀 에디터 https://icechou.tistory.com/327

 

유니티 커스텀에디터 사용하기(인스펙터 컴포넌트 수정)

우선 아래와같은 Enemy라는 스크립트가 있다고 한다면 아래처럼 인스펙터에서 보일것이다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Enemy : MonoBehaviour {     public MonsterType monsterTy..

icechou.tistory.com

C# 딕셔너리 깔끔한 초기화 https://pythonq.com/so/c%23/1734122

 

c# - "사전에 키가없는 경우 새 값 추가"를 포함한 다차원 사전 - IT 툴 넷

c# - "사전에 키가없는 경우 새 값 추가"를 포함한 다차원 사전 출처 c# dictionary initialization

pythonq.com

유니티 데이터 직렬화 https://nforbidden-fruit.tistory.com/28

 

제3장 데이터 보존

Unity エディター拡張入門 Web版無償公開中!Unityエディター拡張の入門書! anchan828.github.io 에디터 확장에서 기능을 구현할 때, 값을 보존해서 다음에도 계속해서 사용할 경우가 있습니다. 이 값

nforbidden-fruit.tistory.com

딕셔너리 컬렉션 초기화(LINQ 사용) https://stackoverflow.com/questions/604831/collection-was-modified-enumeration-operation-may-not-execute

 

Collection was modified; enumeration operation may not execute

I can't get to the bottom of this error, because when the debugger is attached, it does not seem to occur. Collection was modified; enumeration operation may not execute Below is the code. This i...

stackoverflow.com