using UnityEngine; using System.Collections; [System.Serializable] public class LayerData { public LayerData(GameObject _go, string _layerName, int _layerOrder) { go = _go; LayerName = _layerName; LayerOrder = _layerOrder; AddSpaceLayer = 1; } public GameObject go; public string LayerName; public int LayerOrder; public int AddSpaceLayer; public int tempLayerOrderBeforeChange; }
using UnityEngine; using System.Collections; using System.Collections.Generic; public class LayerManager : MonoBehaviour { public List<LayerData> layerDataList = new List<LayerData>(); }
using UnityEngine; using UnityEditor; using UnityEditorInternal; [CustomEditor(typeof(LayerManager))] public class LayerManagerEditor: Editor { private ReorderableList list; private void OnEnable() { list = new ReorderableList(serializedObject, serializedObject.FindProperty("layerDataList"), true, true, true, true); } public override void OnInspectorGUI() { serializedObject.Update(); list.DoLayoutList(); serializedObject.ApplyModifiedProperties(); } }
這裡有幾點可以說明一下
- LayerData 是需要做序列化的,因為我們會在 LayerManager 裡使用它,可以參考上一篇的序列化陣列
- ReorderableList 其實有兩種建構子
- public ReorderableList(IList elements, Type elementType)
- public ReorderableList(SerializedObject serializedObject, SerializedProperty elements)
- 後面四個 Boolean 參數分別代表
- 是否支援拖曳來交換 Element 排序
- 是否顯示標頭
- 是否支援新增按鈕
- 是否支援移除按鈕
private void DrawElementCallback() { // List 中的每一個元件要被畫時,會去 Call 以下的程式碼 // [參數] // rect : 原本每一個元件預設的位置和寬高 // index : 元件是 List 中的第幾個 list.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { // 將元件的序列化參數資料提出來。 // 若用序列化參數來做修改,可以直接改變原本 List 中的參數值,不需要再將欄位的值存回去。 // 另外一個好處是,它可以支援 Undo 的功能 var element = list.serializedProperty.GetArrayElementAtIndex(index); // 每一個元件都間隔 2px rect.y += 2; // [1] 輸入 GameObject 欄位。該欄位是使用 PropertyField 的序列化參數來做修改 // 不需要再將欄位的值存回去,而且可以支援 Undo 的功能 float _width = rect.width / 10.0f; EditorGUI.PropertyField( new Rect(rect.x, rect.y, _width * 3, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("go"), GUIContent.none ); // [2] 輸入圖層欄位。 // GetSortingLayerNames() 可以取得目前專案使用的所有Layer字串 // 因為這裡並不是使用序列化參數來做修改,所以需要再將欄位的值存回 m_Target // 而且它不支援 Undo 的功能 string[] sorting_layer_ary = GetSortingLayerNames(); int target_layer_name_index = System.Array.IndexOf(sorting_layer_ary, m_Target.layerDataList[index].LayerName); int _layer_index = EditorGUI.Popup( new Rect(rect.x + _width * 3, rect.y, _width * 3, EditorGUIUtility.singleLineHeight), target_layer_name_index, sorting_layer_ary ); m_Target.layerDataList[index].LayerName = GetSortingLayerNames()[_layer_index]; EditorUtility.SetDirty(m_Target); // [3] 顯示目前圖層 EditorGUI.LabelField( new Rect(rect.x + _width * 7, rect.y, _width * 1, EditorGUIUtility.singleLineHeight), m_Target.layerDataList[index].LayerOrder.ToString() ); // [4] 和前一個 Index element 的圖層相隔多少 EditorGUI.LabelField( new Rect(rect.x + _width * 8, rect.y, 15, EditorGUIUtility.singleLineHeight), "+" ); if (index == 0) m_Target.layerDataList[index].AddSpaceLayer = 0; EditorGUI.PropertyField( new Rect(rect.x + _width * 8 + 15, rect.y, _width - 15, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("AddSpaceLayer"), GUIContent.none ); // [5] 修正完後的圖層 int _finalLayer = (index == 0) ? init_layer_count + m_Target.layerDataList[index].AddSpaceLayer : m_Target.layerDataList[index-1].tempLayerOrderBeforeChange + m_Target.layerDataList[index].AddSpaceLayer; EditorGUI.LabelField( new Rect(rect.x + _width * 9 + 15, rect.y, _width * 1, EditorGUIUtility.singleLineHeight), _ finalLayer.ToString() ); m_Target.layerDataList[index].tempLayerOrderBeforeChange = _finalLayer; }; }
public string[] GetSortingLayerNames() { System.Type internalEditorUtilityType = typeof(InternalEditorUtility); PropertyInfo sortingLayersProperty = internalEditorUtilityType.GetProperty( "sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic ); return (string[])sortingLayersProperty.GetValue(null, new object[0]); }
以上程式碼只擷取重要的部分,完整程式碼會放在參考資料連結裡。此段的 Editor 程式碼跑起來結果如下圖。
沒有留言:
張貼留言