天天看點

Unity 自定義編輯器視窗的使用

Unity 自定義編輯器視窗功能強大,可以實作所有希望實作的功能。我在近期的項目中仿照魔獸争霸3開發了一套簡單的遊戲機關功能元件,其中包括機關資料、移動方式、動畫播放、武器系統等等。如果用傳統的Inspector來修改各項屬性十分不友善,是以實作一個簡單直覺的自定義編輯器視窗來進行屬性管理成了一個很好的選擇。

建立自定義編輯器視窗并将每一項屬性顯示出來是十分簡單的,我們隻需要通過Selection.activeGameObject 來擷取目前選中的物體,并在從該物體上擷取相關的腳本就可以進行屬性的讀取。但是,如何将修改後的屬性傳遞回指定物體并儲存起來呢?

我的第一想法是通過直接通路物體上的腳本這種方法來指派,下面将舉一個簡單的例子。

假設我的機關系統的移動元件命名為 MovementController 其中speed屬性為移動速度,我在自定義視窗的類中寫如下代碼:

MovementController mc = Selection.activeGameObject.GetComponent<MovementController>();
if (mc != null) 
{
    mc.speed = EditorGUILayout.FloatField(new GUIContent("Speed"), mc.speed);
}
           

這些代碼完成了擷取元件和指派的功能,那麼它的問題在哪裡呢?

使用這些代碼之後,在自定義視窗中進行Speed屬性的修改的确是可以影響到物體上的MovementController 元件的。而且,在修改後立刻進入編輯器的播放模式是可以看出修改效果的。但是這次修改作用的時間也僅僅是目前場景打開的這段時間,一旦你切換場景或是關閉了Unity Editor,所有所做的修改全部會丢失。

究其原因,我們這次修改的是目前場景打開後在記憶體中儲存的執行個體屬性,并不是儲存在硬碟上的場景資料。是以在我們切換場景或是關閉Editor後,随着記憶體的清理,所有修改過的資料也全部一起丢失了。

那麼,怎樣才能算是成功修改到硬碟上的資料,或是通知Editor需要更新硬碟上的資料了呢?

可能細心的朋友會注意到,如果通過Inspector視圖進行場景内某一物體的屬性修改,修改完成後會發現Editor的标題欄會多出一個”*” 來提示使用者目前場景有未儲存的資料。如果這時使用者儲存了目前場景,那麼這個“*”會消失,說明變動已經儲存到硬碟。以此為背景,我們剛剛使用的方法在修改後可以看到Inspector中的對應屬性變化,但是在Editor的标題欄上并不會出現”*”,這也從側面說明Editor并沒有認為這是一次修改,而修改的也僅僅是記憶體中的執行個體。

這裡要引入一個名為“序列化”的概念。序列化 (Serialization)是指将對象的狀态資訊轉換為可以存儲或傳輸的形式的過程。可能隻看定義會有些難以了解,簡單來說就是将記憶體中的資料轉化為能夠儲存到硬碟上的形式。用這句話來解釋也是因為它可以和前面所說的内容對應。前面出現的問題是我修改的僅僅是記憶體中的資料,而我需要把這個資料轉化并存儲到硬碟上,是以序列化就是最好的解決方法。

還用剛才的那個例子,使用序列化方法的代碼如下:

SerializedObject mc = new SerializedObject(Selection.activeGameObject.GetComponent<MovementController>());

SerializedProperty PropSpeed = mc.FindProperty("speed");

PropSpeed.floatValue = EditorGUILayout.FloatField(new GUIContent("Speed"), PropSpeed.floatValue);

mc.ApplyModifiedProperties();
           

這段代碼實作的功能依舊是修改speed屬性,但是與前一個方法不同的地方在于,它并不是直接對記憶體中的執行個體進行修改,而是向将該執行個體進行序列化處理,将它處理為一個SerializedObject,這也就是将其轉化為可以存儲到硬碟上的狀态。再從SerializedObject上擷取SerializedProperty并對SerializedProperty進行修改,就可以保證我們所修改的值是可以存儲到硬碟上的那一部分。最後一句ApplyModifiedProperties 這個函數的功能就像它的名字一樣——應用修改後的屬性。它做的除了将修改後的值同步到執行個體,也通知Editor 這個執行個體進行過修改,需要儲存才能保證修改後的屬性不會丢失。

使用後面這種方法後,在自定義編輯器視窗對Speed屬性進行修改時,會發現Editor的标題欄出現了”*”符号,說明我們的修改生效了,并且可以通過儲存行為将修改後的資料儲存到硬碟中。