簡介:
程序開發中需要連接網絡或在程序外部進行配製的數據,一般不保存在unity自身序列化的文件中。但一些固定的數據類型,利用unity3d自身的序列化功能,配合Editor編程可以方便快速的製作可擴展的數據加載模塊,需要更換數據源也變得十分便利。本文就一個比較複雜的可序列化類,利用Editor窗口編程,實現數據的快速配製。
一、數據模型
1、準備一個數據類DataItem,需要爲類添加Serializable屬性,這樣可以利用unity3d的序列化功能記錄到文件中
[Serializable]
public class DataItem
{
public string name;
public List<float> values;
public string unitName;
#region graph
public bool graph = true;
public string graphName;
public float axisMin;
public float axisMax;
public float axisSize;
#endregion
}
2、還是使用一個更加複雜的類,上面的一個類直接在面版上進行編輯就好了,沒有必要使用EditorWindow到重新寫一遍顯示(其實也是因爲實際項目用到這樣一個複雜的類,順便不用重新寫一個新的)
[Serializable]
public class DataList
{
public string name;
public DataItem key;
public List<DataItem> values;
}
3、寫一個可序列化的對象,並且添加創建菜單(同時這個對象創建出來後在Inspactor面版上所顯示的數據變得異常複雜)
[CreateAssetMenu(fileName = "LoadForceDataObject.asset", menuName = "生成/加載數據")]
public class LoadForceDataObject : ScriptableObject {
public List<DataList> dataList;
}
4、在Inspactor面版上的顯示效果如下,顯然在這樣的面版中進行數據配製十分困難(還只設置了一個DataList和其中一個Key,,,)
二、設計人性化的配製面版
1、分析數據類型
在窗口界面中應該有一個放置數據源的輸入框,在有數據的情況下可以顯示一個大的可縮放的可視化區域,這其中每一個DataList對象顯示爲一個小的固定大小的區域,在其中至少有一個固定的DataItem作爲Key,DataItem中其中的Values不想一個一個填寫,要求可以進行對一個串以符號分割的字符串進行split,自動加載到其中去。
2、繪製草圖
按以上的思路進行設計,可以做出以下的草圖
三、實現細節
1、建立窗口類,並實現窗口打開。按如下腳本可以實現一個editor模式下的指定大小的小窗口
public class DataTableWindow : EditorWindow
{
[MenuItem("Window/DataTable")]
static void CreateWindow()
{
EditorWindow window = EditorWindow.GetWindow<DataTableWindow>("數據配製", true);
window.position = new Rect(200, 300, 600, 400);
window.maxSize = new Vector2(600, 400);
}
}
2、繪製數據源,實現效果如下圖所示
void DrawHead()
{
using (var scope = new EditorGUILayout.HorizontalScope())
{
GUI.Box(scope.rect, new GUIContent());
EditorGUILayout.SelectableLabel("數據源", LayoutOption.shortWidth);
dataObj = EditorGUILayout.ObjectField(dataObj, typeof(LoadForceDataObject), false, LayoutOption.longWidth) as LoadForceDataObject;
}
}
3、繪製一個List添加功能按扭, 輸入框內放入創建的asset格式的數據源後,開始是沒有數據的,因此需要一個按扭來創建一個DataList是沒有數據的,因此需要一個按扭來創建一個DataList 並加入到這個對象中,效果如下圖所示。使用HorizontalScope這不必要,主要是考慮到還有一些其他的操作功能也可以加入到其中
void DrawListsTools()
{
using (var scope = new EditorGUILayout.HorizontalScope())
{
GUI.backgroundColor = Color.blue;
if (GUILayout.Button("+", LayoutOption.shortWidth))
{
dataLists.Add(new DataList());
}
GUI.backgroundColor = Color.white;
}
}
4、繪製可滑動的實體區域,bodyScorll 是一個全局變量,用來保存當前的滑動所處的狀態。dataLists是數據源對象所包含的所有DataList,在這其中將繪製的功能再次分爲繪製DataList的標題頭和數據體。
void DrawBody()
{
using (var scope = new EditorGUILayout.ScrollViewScope(bodyScorll))
{
bodyScorll = scope.scrollPosition;
foreach (var item in dataLists)
{
using (var vscope = new EditorGUILayout.VerticalScope())
{
GUI.Box(vscope.rect, new GUIContent());
if (DrawListHeader(item))
{
DrawListBody(item);
GUILayout.Space(EditorGUIUtility.singleLineHeight);
}
else
{
continue;
}
}
}
if (waitDeleteList != null)
{
dataLists.Remove(waitDeleteList);
}
}
}
帶有返回值的LitstHeader繪製可以實現數據體的展開和隱藏
bool DrawListHeader(DataList list)
{
using (var scope = new EditorGUILayout.HorizontalScope())
{
if (!viewDic.ContainsKey(list))
{
viewDic.Add(list, true);
}
if (viewDic[list] = GUILayout.Toggle(viewDic[list], list.name,LayoutOption.mediaHigh))
{
GUI.backgroundColor = Color.green;
GUI.Box(scope.rect, "");
GUI.backgroundColor = Color.white;
EditorGUILayout.LabelField("ListName", LayoutOption.longWidth);
list.name = EditorGUILayout.TextField(list.name, LayoutOption.longWidth);
list.values = list.values ?? new List<DataItem>();
GUI.backgroundColor = Color.blue;
if (GUILayout.Button("+", LayoutOption.minWidth))
{
list.values.Add(new DataItem());
}
GUI.backgroundColor = Color.white;
return true;
}
else
{
GUI.backgroundColor = Color.red;
if (GUILayout.Button("-", LayoutOption.minWidth))
{
waitDeleteList = list;
}
GUI.backgroundColor = Color.white;
return false;
}
}
}
5、其他細節就沒有太多了,github地址爲:https://github.com/zouhunter/Editor_Extends(後續有相關的編輯器學習使用的腳本會同步到其中)
四、最終截圖:(在這樣的環境進行配製貌似省心了不少吧)