UGUI内核大探究(一)EventSystem
2019獨角獸企業重金招聘Python工程師標準>>>
UGUI是Unity3D官方推出的UI系統,為了更好的使用UGUI,我們就需要去了解它。
UGUI代碼開源,我們可以從bitbucket下載到源碼。
雖然Unity官方喜歡藏著掖著,例如RectTransform和Canvas系列的源碼都放在了UnityEngine里面,但是這并不妨礙我們對已開源的代碼進行分析(其實多少也有些妨礙吧。。。)
今天我們就探究了一下UGUI的事件系統EventSystem。
雖然名字起得很大,但是實際上EventSystem處理和管理的其實是點擊、鍵盤輸入、觸摸等事件,所以應該成為輸入事件系統InputEventSystem更為恰當。
我們看到EventSystem最開始聲明了一個List和一個變量
[csharp]?view plain?copyprivate?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便調用:
而這個方法會將各種輸入事件(如點擊、拖拽等事件)傳遞給EventSystem當前選中的GameObject(m_CurrentSelected)。
[csharp]?view plain?copym_CurrentInputModule.Process();??而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屬性:
[csharp]?view plain?copypublic?static?EventSystem?current?{?get;?set;?}??
因為是靜態屬性,所以只存在一個current,而并不會每個實例對象會有一個.
?
當一個EventSystem組件OnEnable的時候會將這個對象賦值給current。參考OnEnabled與OnDisabled。
[csharp]?view plain?copyprotected?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)。參考OnEnabled與OnDisabled。
?
[csharp]?view plain?copyprotected?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本身并沒有太多東西,但是畢竟輸入模塊里面還是保存了一些數據的。
轉載于:https://my.oschina.net/u/2874878/blog/1594641
總結
以上是生活随笔為你收集整理的UGUI内核大探究(一)EventSystem的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 并发容器CopyOnWriteArray
- 下一篇: Guava Cache 1(脉络)