我正在 Unity 中创建 RPG 游戏。最近,我成功地实现了 HashSet 的自定义检查器。但是,有两个主要问题我需要帮助。
1) 使用 Itemslot.cs 对预制件/对象上的哈希集进行的更改有效,但只会持续到我退出 Unity 为止。此外,当我对预制件进行更改并将其拖动到场景时,新创建的对象具有其 HashSet,而无需我之前对预制件进行任何更改。
2) 自从实现此功能以来,当我对 .cs 文件进行更改并尝试编译时,编辑器有时会无限期地卡住。
它的外观:
Itemslot.cs
public class Itemslot : MonoBehaviour, IDropHandler, IPointerEnterHandler, IPointerExitHandler
{
[System.Serializable]
public class HashSetItemType : HashSet<GlobalEnums.ItemType> { }
public HashSetItemType typeAllowed = new HashSetItemType();
[System.Serializable]
public class HashSetClassType : HashSet<GlobalEnums.GameClasses> { }
public HashSetClassType classAllowed = new HashSetClassType();
public int inventoryIndex;
public GameObject socket;
}
ItemslotEditor.cs
[CustomEditor(typeof(Itemslot))]
public class ItemslotEditor : Editor
{
public override void OnInspectorGUI()
{
serializedObject.Update();
Itemslot component = (Itemslot)target;
GUILayout.BeginVertical("box");
EditorGUILayout.PropertyField(serializedObject.FindProperty("socket"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("inventoryIndex"));
var style = new GUIStyle(GUI.skin.button);
int counter = 0;
EditorGUILayout.LabelField("Allowed Types");
GUILayout.BeginHorizontal();
foreach (GlobalEnums.ItemType t in Enum.GetValues(typeof(GlobalEnums.ItemType)))
{
if (counter % 3 == 0 && counter > 1)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
}
if (component.typeAllowed.Contains(t))
{
GUI.backgroundColor = Color.green;
}
else
{
GUI.backgroundColor = Color.white;
}
if (GUILayout.Button(t.ToString(), style, GUILayout.Width(120), GUILayout.Height(30)))
{
if (component.typeAllowed.Contains(t))
{
component.typeAllowed.Remove(t);
}
else
{
component.typeAllowed.Add(t);
}
}
counter++;
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUI.backgroundColor = Color.red;
if (GUILayout.Button("NONE", style, GUILayout.Width(150), GUILayout.Height(25)))
{
component.typeAllowed.Clear();
}
GUI.backgroundColor = Color.yellow;
if (GUILayout.Button("ALL", style, GUILayout.Width(150), GUILayout.Height(25)))
{
foreach (GlobalEnums.ItemType t in Enum.GetValues(typeof(GlobalEnums.ItemType)))
{
component.typeAllowed.Add(t);
}
}
GUILayout.EndHorizontal();
EditorGUILayout.LabelField("Allowed Classes");
counter = 0;
GUILayout.BeginHorizontal();
foreach (GlobalEnums.GameClasses t in Enum.GetValues(typeof(GlobalEnums.GameClasses)))
{
if (counter % 3 == 0 && counter > 1)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
}
if (component.classAllowed.Contains(t))
{
GUI.backgroundColor = Color.green;
}
else
{
GUI.backgroundColor = Color.white;
}
if (GUILayout.Button(t.ToString(), style, GUILayout.Width(120), GUILayout.Height(30)))
{
if (component.classAllowed.Contains(t))
{
component.classAllowed.Remove(t);
}
else
{
component.classAllowed.Add(t);
}
}
counter++;
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUI.backgroundColor = Color.red;
if (GUILayout.Button("NONE", style, GUILayout.Width(150), GUILayout.Height(25)))
{
component.classAllowed.Clear();
}
GUI.backgroundColor = Color.yellow;
if (GUILayout.Button("ALL", style, GUILayout.Width(150), GUILayout.Height(25)))
{
foreach (GlobalEnums.GameClasses t in Enum.GetValues(typeof(GlobalEnums.GameClasses)))
{
component.classAllowed.Add(t);
}
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
}
最佳答案
Unity 无法序列化 HashSet<T>
,因此您的更改永远不会保存到磁盘。
这里有两个选择:
- 使用
List<T>
。这种类型可以被Unity序列化,只要T
也可以序列化。 - 实现ISerializationCallbackReceiver自己处理序列化,例如序列化时将 HashSet 的内容存储在 List 中,反序列化时将它们移回到 HashSet 中。请参阅https://docs.unity3d.com/Manual/script-Serialization-Custom.html
编辑
以下是如何使用 ISerializationCallbackReceiver
执行此操作的示例界面。
public class Itemslot : MonoBehaviour, IDropHandler, IPointerEnterHandler,
IPointerExitHandler, ISerializationCallbackReceiver
{
public HashSet<GlobalEnums.ItemType> typeAllowed = new HashSet<GlobalEnums.ItemType>();
// private field to ensure serialization
[SerializeField]
private List<GlobalEnums.ItemType> _typeAllowedList = new List<GlobalEnums.ItemType>();
public void OnBeforeSerialize()
{
// store HashSet contents in List
_typeAllowedList.Clear();
foreach(var allowedType in typeAllowed)
{
_typeAllowedList.Add(allowedType);
}
}
public void OnAfterDeserialize()
{
// load contents from the List into the HashSet
typeAllowed.Clear();
foreach(var allowedType in _typeAllowedList)
{
typeAllowed.Add(allowedType);
}
}
}
关于c# - Unity 中 HashSet 的自定义检查器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46676915/