이런 식으로 리스트 형태 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
참고 사이트 :
유니티 직렬화 콜백 공식 문서 https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html
유니티 커스텀 에디터 https://icechou.tistory.com/327
C# 딕셔너리 깔끔한 초기화 https://pythonq.com/so/c%23/1734122
유니티 데이터 직렬화 https://nforbidden-fruit.tistory.com/28
딕셔너리 컬렉션 초기화(LINQ 사용) https://stackoverflow.com/questions/604831/collection-was-modified-enumeration-operation-may-not-execute