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 程式碼跑起來結果如下圖。

沒有留言:
張貼留言