1. 程式人生 > >UGUI核心大探究(一)EventSystem

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的值變化了並且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本身並沒有太多東西,但是畢竟輸入模組裡面還是儲存了一些資料的。