譯林軍 灰魅|2014-03-04 10:52|10589次浏覽|Unity(315)移動應用(31)技術開發(16)0
在這篇Unity C#的文章中,你將會創建一個簡單的數據結構,然後寫下它的屬性抽屜。
下面你將會學到如何創建。
在此之前,你需要了解Unity的編輯器,以及Uinty C#的一些腳本。如果你已經學習了一些其它的課程,這將會讓你更加容易上手。
這篇文章適合Unity 4.3或者以上的版本。老版本仍然可以在這裡找到。
被壓縮的色點
色點
Unity有很多種類的的數據類型,你可以用這些數據去制作很多自定義組件。但是有時我們需要一些小的自定義數據,它可以在很多地方使用。與其重復寫同樣的代碼,倒不如選擇一些可以重復使用,而且十分簡單的封裝數據類,例如一些內置的數據類型。
我們將要創建一些色點,這個數據結構是同時包括顏色和位置。
我們首先創建一個新的空項目工程,然後添加一個名為ColorPoint的新的C#腳本,同時添加所需的變量。
1 2 3 4 5 6 7using UnityEngine;
public class ColorPoint {
public Color color;
public Vector3 position;
}
然後我們再創建一個叫ColorPointTester的類來測試我們剛剛創建的數據類型。我們給它一個單獨的點向量和一個數組向量,同時也比較單獨的點向量和數組向量。接著我們創建一個空的游戲物體,把它添加到裡面。
1
2
3
4
5
6
7
8
9
10
11
12
using UnityEngine;
public class ColorPointTester : MonoBehaviour {
public ColorPoint point;
public ColorPoint[] points;
public Vector3 vector;
public Vector3[] vectors;
}
色點和空測試器。
新的數據類型不能在inspector中看到,因為他的內容還不能被保存。我們要解決這個問題就要把這個數據類型添加到系統中。被序列化後屬於我們的類.在執行這步是,這個類可能要在所有公共地方的數據流可以序列化,然後才能被存儲起來。
1 2 3 4 5 6 7 8 9using UnityEngine;
using System;
[Serializable]
public class ColorPoint {
public Color color;
public Vector3 position;
}
現在我們剛自定義的數據可以再inspector中顯示了,我們可以再任何地方編輯、保存。同樣的,把我們的測試對象通過拖拽到項目視圖的預設中,然後在場景中改變一些變量的實例。這可以證明這類數據可以在預設中正常運行。
正常的對象和一個調整的實例預設。inspector看起來很混亂。這可以有所修改,讓它通過拖動變寬一些,但如果它的寬度過大,向量將會崩潰。
一個充實的inspector。
繪圖屬性
很可惜,即使有較寬的inspector,我們仍需要多行色點。
幸運的是,我們可以用自定義的變量在編輯中替換Unity的默認繪圖屬性。這可以通過擴展UnityEditor.PropertyDrawer來創建一個類,同時用 UnityEditor.CustomPropertyDrawer來匹配我們想要繪制的相關內容。然後,命名一個叫ColorPointDrawer的類,因為這是一個編輯的類,我們會把它放在一個叫Editor新的文件夾裡面。
1 2 3 4 5 6using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(
typeof
(ColorPoint))]
public class ColorPointDrawer : PropertyDrawer {
}
這是不做任何處理的屬性抽屜。
現在inspector不再顯示任何有用的東西,但是我們可以改變,通過覆蓋在OnGUI上,來默認自定義版本的屬性抽屜。
這個OnGUI方法有三個參數。第一個是一個巨型,它是告訴我們那些窗口的區域是應該使用什麼來繪制屬性。第二個是自身的屬性,由一個SerializedProperty來表示。第三個是GUIContent,定義了我們應該使用的屬性標簽。
讓我們首先用GUIEditor.PropertyField的方法找准位置,然後繪制GUIEditor.PrefixLabel。
1 2 3 4public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
EditorGUI.PrefixLabel(position, label);
EditorGUI.PropertyField(position, property.FindPropertyRelative(
"position"
));
}
屬性抽屜的重疊標簽。
當我們鎖定位置後,它的標簽就是重疊標簽的色點。接下來,我們要通過用GUIContent.none.來重寫它。
1 2 3 4public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
EditorGUI.PrefixLabel(position, label);
EditorGUI.PropertyField(position, property.FindPropertyRelative(
"position"
), GUIContent.none);
}
一個依舊重疊的標簽
向量仍然是重疊標簽,因為我們使用的是同樣的位置矩形,接下來,我們將用這個矩形進行替換。
1 2 3 4public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"position"
), GUIContent.none);
}
即使不正確的定位,也不再重疊。
這看起來好了很多,但放置位置向量的數組元素太過於偏右。導致這個發生的原因是PropertyField方法調整當前的編輯器縮進級別。
通過靜態初始化EditorGUI.indentLevel的方法,設置縮進的級別。為了暫時的消除自動縮進,我們只要將其設置為零即可。
1 2 3 4 5public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"position"
), GUIContent.none);
}
正確定位
原文鏈接:http://catlikecoding.com/unity/tutorials/editor/custom-data/
修改Prefix
當prefix標簽變成粗體,顯示調整過的預制值時,它就無法進行任何操作。所以我們既不能立即恢復整個彈辨色點(color point),也不能輕易刪除或復制prefix標簽的數組元素。
我們需要在編輯器中設定屬性生效的起始位置,因為目前我們僅僅展示了一部分內容。我們可以使用EditorGUI。利用BeginProperty類函數創建一個新標簽,並標志著一個屬性的出現,然後使用EditorGUI。利用EndProperty類函數表示屬性的終止。這樣我們就可以通過上下文菜單(context menu)獲得擁有預期功能的標簽。
1 2 3 4 5 6 7
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
label = EditorGUI.BeginProperty(position, label, property);
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"position"
), GUIContent.none);
EditorGUI.EndProperty();
}
恢復及數組功能支持
添加顏色
現在該設定顏色屬性了。為了使其在一條線上,我們必須減少矢量所占空間。由於矢量由三部分組成而顏色作為其第四部分,我們將把向量置於前75%的水平空間,把顏色置於其余的25%空間中。我們也使用單字母命名顏色標簽。
1 2 3 4 5 6 7 8 9 10 11
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
label = EditorGUI.BeginProperty(position, label, property);
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
contentPosition.width *= 0.75f;
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"position"
), GUIContent.none);
contentPosition.x += contentPosition.width;
contentPosition.width /= 3f;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"color"
),
new
GUIContent(
"C"
));
EditorGUI.EndProperty();
}
帶顏色,但有誤。
盡管我們的標簽很短,但是它依然占據較多空間,導致顏色數據被擠到右側。這是因為無論內容長短,標簽寬度都是固定的。你可以通過調整EditorGUIUtility.labelWidth.改變標簽寬度。設置14個像素的寬度效果更佳。
1 2 3 4 5 6 7 8 9 10 11 12
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
label = EditorGUI.BeginProperty(position, label, property);
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
contentPosition.width *= 0.75f;
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"position"
), GUIContent.none);
contentPosition.x += contentPosition.width;
contentPosition.width /= 3f;
EditorGUIUtility.labelWidth = 14f;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"color"
),
new
GUIContent(
"C"
));
EditorGUI.EndProperty();
}
尺寸正好的顏色標簽。
索取額外一行
默認像素可以在單行與雙行之間轉變,這取決於inspector的寬度。我們也可以這麼做。
我們必須覆蓋GetPropertyHeight method,爭取更多的垂直空間。一行的默認值是16個像素。再添加一行需要另外18個像素(包括第二行自身的16個像素及兩行間距的2個像素)。
當我們使用inspector面板時,屏幕寬度實際上就包含它的寬度,所以我們可以利用這一點。當寬度減小到333以下時,像素會轉換至多行,因此我們也要這麼做。
1 2 3
public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
return
Screen.width < 333 ? (16f + 18f) : 16f;
}
索取更多空間。
當我們把inspector寬度調小到一定程度時,就能獲得更多的垂直空間。然而,我們尚且還不能這麼做。為了實現這一目標,我們必須注意以下四點內容。
第一,通過檢查position長方形的高度,可以發現我們正在使用雙行。第二,我們需要將高度調回到16個像素,以便顏色屬性能夠保留在同一行。第三,畫完屬性標簽後,我們必須將其下移一行。第四,通過利用EditorGUI IndentedRect method,我們必須增加一級縮進級別,將其應用至position。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
label = EditorGUI.BeginProperty(position, label, property);
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
if
(position.height > 16f) {
position.height = 16f;
EditorGUI.indentLevel += 1;
contentPosition = EditorGUI.IndentedRect(position);
contentPosition.y += 18f;
}
contentPosition.width *= 0.75f;
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"position"
), GUIContent.none);
contentPosition.x += contentPosition.width;
contentPosition.width /= 3f;
EditorGUIUtility.labelWidth = 14f;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative(
"color"
),
new
GUIContent(
"C"
));
EditorGUI.EndProperty();
}
利用更多空間。
現在,我們對彈辨色點(color point)有了一個精彩簡短的描述。它支持取消(undo),重寫(redo),預制(prefabs)以及多目標編輯。如果inspector足夠寬,它只占一行,否則,占兩行。
接下來的editor教程涉及自定義列表(Custom List)。
已下載的數據資料
custom-data.unitypackage
已完成的項目。