|
unity3d的方便之處在于,它很容易地擴(kuò)展編輯器套件。每款游戲都對加工有著不同的需求,可以快速地以完全集成的方法來構(gòu)建這些內(nèi)容并極大地提升開發(fā)速度。 目前有大量復(fù)雜的軟件包提供以基本Unity功能套件為基礎(chǔ)的復(fù)雜工具,從視覺腳本編輯器到編輯器內(nèi)導(dǎo)航網(wǎng)格生成。但是,有關(guān)如何自行構(gòu)建此類事物的程序說明卻很少。我將在下文列舉某些在自己的工作中總結(jié)的編輯器定制相關(guān)信息。
Unity-Window(from gamasutra) 如何構(gòu)建編輯器腳本 因為你不想在游戲中包含所有的編輯器定制,而且你也不想游戲?qū)δ承︰nity編輯器內(nèi)的東西有所依賴,所以Unity將運(yùn)行時間和編輯器代碼放置在單獨(dú)的編譯中。 在編輯命令中,運(yùn)行時間代碼在編輯器代碼之前執(zhí)行,這樣編輯器類型就可以可靠地聯(lián)系至運(yùn)行時間組件(游戲邦注:否則就會變得難以編輯),但是你的運(yùn)行時間組件并不涉及任何編輯器代碼。 你必須維持嚴(yán)格的層次。Unity 3.4版本中這個方面做得更加具體,現(xiàn)在其產(chǎn)生的項目文件與其提供的4個編輯階段相對應(yīng),這樣就不會混淆文件的構(gòu)建時間。 在某個點(diǎn)上的程序說明有些不太清楚。當(dāng)我首次開始使用時,我認(rèn)為需要在我的項目上創(chuàng)建單個“Editor”文件夾,然后把所有的編輯器類型放入其中。事實(shí)上,系統(tǒng)的靈活性要更高些,你可以在項目中創(chuàng)建任意數(shù)量的“Editor”文件夾,將其埋藏在“資產(chǎn)”文件夾的任何地方,所有這些都可以存放編輯器代碼。 所以,現(xiàn)在通常情況下我會以功能(游戲邦注:比如命名為“AI”)為單位來創(chuàng)建文件夾,然后納入所有功能相關(guān)組件,然后在旁邊放上Editor文件夾(游戲邦注:比如命名為“AI/Editor”),裝上所有運(yùn)行這些組件的編輯器擴(kuò)展。 只要Unity的內(nèi)在類型能夠發(fā)揮作用,運(yùn)行時間類型都會存在于UnityEngine命名空間中,而所有的編輯器類型都會存在于UnityEditor命名空間里。
unity-projectlist(from gamasutra) UnityEditor.Editor類 到目前為止,我設(shè)立的最普遍的定制是一個自定義檢查器。Unity的Inspector面板提供看到組件狀態(tài)的窗口,但是這種基本設(shè)置只能理解有限的類型,而且只能展示公共區(qū)域。 自定義檢查器讓你可以完全控制用戶查看和編輯你的組件的方式。比如,它們可以讓你呈現(xiàn)只讀資產(chǎn)、強(qiáng)迫性價值限制或只改變選項呈現(xiàn)的方式。 Unity中的Inspector都是Editor類的子類別,所以你應(yīng)該從這里開始。但是,我對編輯器類處理樣式的方法不是很喜歡。里面有個“Target”用來提及檢查器正在編輯的物體,但是只是基本的“Object”樣式,所以你要不斷將其轉(zhuǎn)變成更有用的樣式。為避開這個問題,我使用了一個非常簡單的類別,具體如下: public class InspectorBase : Editor where T : UnityEngine.Object { protected T Target { get { return (T) target; } } } 現(xiàn)在,如果我想要為MyCustomComponent創(chuàng)造檢查器,我就可以從InspectorBase得到檢查器,然后使用“Target”,這樣我就不用時常更改了。 應(yīng)當(dāng)注意的是,你還需要將CustomEditor屬性附到檢查器類中,Unity才能夠真正使用它們。 編輯器GUI 一旦你創(chuàng)造自定義檢查器后,你通常想要執(zhí)行的方法就是OnInspectorGUI()。OnInspectorGUI()可用來指定在檢查器中展示的所有東西,使用的是Unity的GUI系統(tǒng)。 因為這是編輯器代碼,我們可以使用UnityEditor命名空間中的類型,這包括EditorGUILayout。EditorGUILayout使得了大量的簡單控制,可以在編輯器中使用,比Unity普通運(yùn)行時間GUI系統(tǒng)提供的更好。比如,假如我想向用戶展示進(jìn)入3D位置的領(lǐng)域,我可以使用EditorGUILayout.Vector3Field():Target.somePosition = EditorGUILayout.Vector3Field(“Some position”, Target.somePosition)。 在檢查器中產(chǎn)生的效果如下圖所示:
unity-vec3field(from gamasutra) 正因為GUI系統(tǒng)能夠發(fā)揮作用,所以如果我改變UI中的值,Vector3Field就會傳回新的值,Target.somePosition就會得到更新。在將其指派給目標(biāo)之前,你可以自由改變值(游戲邦注:比如將值定義在某個范圍內(nèi)),你也可以完全忽略傳回的值。 值并不一定來自于域,你可以曝光檢查器中的資產(chǎn),可以采用調(diào)用一個功能來獲得當(dāng)前值并使用另一個功能來保存。 當(dāng)然,Unity會默認(rèn)處理這個事情。如果你只是想要在Unity已經(jīng)展示的為基礎(chǔ)來構(gòu)建,你就不必要重新執(zhí)行所有那些域。Editor有個DrawDefaultInspector()方法,告訴Unity調(diào)用所有通常調(diào)用的控制,但是在這個過程完成之后,你仍然有機(jī)會添加額外域和按鍵。 說到按鍵,EditorGUILayout的用途確實(shí)很廣泛,但是你或許已經(jīng)注意到存在漏洞。比如,如果我想要在導(dǎo)航網(wǎng)格組件上添加“重新計算”按鍵,這又會怎么樣呢?技巧在于EditorGUILayout仍然構(gòu)建于常規(guī)運(yùn)行時間GUILayout之上,所以你還是可以使用GUILayout中的所有東西。 你對檢查器中的域做出改變并且為目標(biāo)物體的域指派新值時,Unity會察覺到你正在改變物體,所以下次保存屏幕或項目時就會將其寫入磁盤。這種察覺是有限的,它只能識別公共資產(chǎn)的直接指派。如果你通過資產(chǎn)或調(diào)用方法來修改目標(biāo)物體,你可能就需要自行調(diào)用EditorUtility.SetDirty了。 擴(kuò)展組件背景菜單 在測試時,有時手動引發(fā)某些行為還是很有用的。你可以通過在自定義檢查器上安放按鍵來觸發(fā)行為:if(GUILayout.Button(“Explode now!”)) Target.ExplodeNow()。 但是還有個更加簡單的方法,這個方法完全不需要自定義檢查器。你可以使用的是UnityEngine.ContextMenu屬性: /* In the target class… */ [ContextMenu("Explode now!")] public void ExplodeNow() { … } 右鍵點(diǎn)擊組件的檢查器(游戲邦注:無論是否自定義化),你會看到背景菜單,其中有額外的功能??梢钥焖俚剡M(jìn)行測試。 擴(kuò)展主菜單 到這里為止,我所說的所有東西都是圍繞某個特別組件為中心的定制。其他種類的擴(kuò)展又會如何呢? 在我的游戲中,動畫系統(tǒng)將其資產(chǎn)存放在文件夾架構(gòu)中,這樣每個文件夾都對應(yīng)enum的一個入口。當(dāng)我改變enum時,如果可以同步文件夾結(jié)構(gòu)會起到很大作用,添加任何丟失的文件夾并刪除 任何多余的文件夾。所以我采用了以下較為簡單的方法: public class AnimationSystem{ public static void SyncFolderStructure() { … } } 但是我要何時以及如何調(diào)用呢?我采用的做法是將其連同到Assets菜單中的菜單項目中,使用MenuItem屬性: [MenuItem("Assets/Sync folder structure")] public static void SyncFolderStructure() { … } 點(diǎn)擊菜單項目就可以調(diào)用功能。應(yīng)當(dāng)注意的是,功能需要是靜態(tài)的,但是其中的類可以是多種類型的。 Wizards Editor GUI元素并不一定要在Inspector中。它還可以創(chuàng)造主觀編輯器窗口,可以像任何Unity內(nèi)置窗口那樣一動,而且可以像在檢查器中那樣使用GUI命令。最簡單的方法就是使用ScriptableWizard,這很像一個對話盒。你在呈現(xiàn)后設(shè)定某些值,然后點(diǎn)擊按鍵讓其施展“魔法”。
unity-ragdollwizard(from gamasutra) 在默認(rèn)情況下,ScriptableWizard的作用很像檢查器:類中的任何公共域都會自動呈現(xiàn)在wizard窗口中。你的wizard會像一大串公共域那樣簡單,而且還有個OnWizardCreate()方法,當(dāng)用戶點(diǎn)擊“Create”按鍵時Unity就會調(diào)用這個方法。而且,你可以改變按鍵上的文字,“Apply”或“OK”之類的會顯得更加直觀。 wizard的另一個層面是決定用戶如何開啟,常用方法是使用有靜態(tài)功能的菜單選項,如上圖所示: [MenuItem("GameObject/Create Other/Explosion")] public static void CreateExplosion() { ScriptableWizard.DisplayWizard(“Create explosion”); } |
|
|