UGUI核心大探究(一)EventSystem
UGUI是Unity3D官方推出的UI系統,為了更好的使用UGUI,我們就需要去了解它。
UGUI程式碼開源,我們可以從bitbucket下載到原始碼。
雖然Unity官方喜歡藏著掖著,例如RectTransform和Canvas系列的原始碼都放在了UnityEngine裡面,但是這並不妨礙我們對已開源的程式碼進行分析(其實多少也有些妨礙吧。。。)
今天我們就探究了一下UGUI的事件系統EventSystem。
雖然名字起得很大,但是實際上EventSystem處理和管理的其實是點選、鍵盤輸入、觸控等事件,所以應該成為輸入事件系統InputEventSystem更為恰當。
我們看到EventSystem最開始聲明瞭一個List和一個變數
private List<BaseInputModule> m_SystemInputModules = new List<BaseInputModule>();
private BaseInputModule m_CurrentInputModule;
系統輸入模組表和當前輸入模組。
BaseInputModule是一個抽象類,PointerInputModule繼承自它,同樣也是抽象類,而StandaloneInputModule和TouchInputModule又繼承自PointerInputModule。StandaloneInputModule是面向“PC,
Mac& Linux Standalone”這個平臺的輸入模組,而TouchInputModule是面向“iOS”、“Android”等可觸控移動平臺的輸入模組。
EventSystem會每一幀都處理這些輸入模組,首先是呼叫TickModules方法,更新每一個InputModule。
然後遍歷m_SystemInputModules判斷這些module是否支援當前的平臺(例如StandaloneInputModule需要判斷是否滑鼠已連線,而TouchInputModule需要判斷是否支援觸控)且module是否可啟用(可啟用條件祥參StandaloneInputModule和TouchInputModule的原始碼)。
如果有符合條件的module便賦值給m_CurrentInputModule(當前輸入模組)並break。
如果沒有符合條件的module便選取第一個支援當前平臺的module作為
最後如果m_CurrentInputModule的值變化了並且m_CurrentInputModule不為null便呼叫:
m_CurrentInputModule.Process();
而這個方法會將各種輸入事件(如點選、拖拽等事件)傳遞給EventSystem當前選中的GameObject(m_CurrentSelected)。
而m_CurrentSelected大部分情況是Selectable元件(繼承自它的有Button、Dropdown、InputField等元件)設定的,相關程式碼我們會在後續的文章中介紹。
而設定m_CurrentSelected的時候,會通過ExecuteEvents這個類對之前的物件執行一個被取消事件,且對新選中的物件執行一個被選中事件。這就是OnSelect和OnDeselect兩個方法的由來。
EventSystem的RaycastAll方法使用射線從相機到某個點(設為點E)照射在UI上,然後對被照射到的所有物件進行排序,大致是遠近排序。
而這個方法實在PointerInputModule中使用的,如果點選(或觸控)事件移動的時候,被該事件影響的物件也會發生變化,通過RaycastAll方法(傳入的eventData中的position屬性作為點E)獲得到第一個被射線照射到的物件,如果與之前的物件不同,便變更物件(同時會回撥原物件的OnPointerExit和新物件的OnPointerEnter方法)。
IsPointerOverGameObject是EventSystem類裡特別常用的一個方法,用於判斷是否點選在UI上,具體是在PointerInputModule中實現的,以後我們研究UGUI的輸入模組的時候會深入講解,概括一下就是判斷當前是否存在某個鍵位(預設是-1滑鼠左鍵)的資料。
最後我們注意到EventSystem有一個static屬性:
public static EventSystem current { get; set; }
因為是靜態屬性,所以只存在一個current,而並不會每個例項物件會有一個.
當一個EventSystem元件OnEnable
protected override void OnEnable()
{
base.OnEnable();
if (EventSystem.current == null)
EventSystem.current = this;
#if UNITY_EDITOR
else
{
Debug.LogWarning("Multiple EventSystems in scene... this is not supported");
}
#endif
}
OnDisable的時候會將current賦值為null(當current==this)
protected override void OnDisable()
{
if (m_CurrentInputModule != null)
{
m_CurrentInputModule.DeactivateModule();
m_CurrentInputModule = null;
}
if (EventSystem.current == this)
EventSystem.current = null;
base.OnDisable();
}
這就是為什麼我們在Unity Editor裡面增加多個EventSystem的時候會報警告。
當然在遊戲執行的時候,我們也不能隨意的增加刪除EventSystem,一來似乎並沒有什麼必要,二來雖然EventSystem本身並沒有太多東西,但是畢竟輸入模組裡面還是儲存了一些資料的。