unity5.0開發了新的UI系統UGUI,附帶的事件系統EventSystem不只能夠用於UI,對於場景中的對象也一樣適用。網絡上有不少使用說明,可是僅僅是怎麼用而已……這篇文章是我翻了無數遍官方手冊整理出來的,包括本身的理解,還有官方文檔的傳送門,也許你會有興趣。html
1、EventSystem對象的說明網絡
當咱們在場景中建立任一UI對象後,Hierarchy面板中均可以看到系統自動建立了對象EventSystem,能夠看到該對象下有三個組件:EventSystem、StandaloneInputModule、TouchInputModule,後面兩個組件都繼承自BaseInputModule。app
EventSystem組件主要負責處理輸入、射線投射以及發送事件。一個場景中只能有一個EventSystem組件,而且須要BaseInputModule類型組件的協助才能工做。EventSystem在一開始的時候會把本身所屬對象下的BaseInputModule類型組件加到一個內部列表,而且在每一個Update週期經過接口UpdateModules接口調用這些基本輸入模塊的UpdateModule接口,而後BaseInputModule會在UpdateModule接口中將本身的狀態修改爲'Updated',以後BaseInputModule的Process接口才會被調用。
BaseInputModule是一個基類模塊,負責發送輸入事件(點擊、拖拽、選中等)到具體對象。EventSystem下的全部輸入模塊都必須繼承自BaseInputModule組件。StandaloneInputModule和TouchInputModule組件是系統提供的標準輸入模塊和觸摸輸入模塊,咱們能夠經過繼承BaseInputModule實現本身的輸入模塊。ide
除了以上兩個組件,還有一個很重要的組件經過EventSystem對象咱們看不到,它是BaseRaycaster組件。BaseRaycaster也是一個基類,前面說的輸入模塊要檢測到鼠標事件必須有射線投射組件才能肯定目標對象。系統實現的射線投射類組件有PhysicsRaycaster, Physics2DRaycaster, GraphicRaycaster。這個模塊也是能夠本身繼承BaseRaycaster實現個性化定製。函數
總的來講,EventSystem負責管理,BaseInputModule負責輸入,BaseRaycaster負責肯定目標對象,目標對象負責接收事件並處理,而後一個完整的事件系統就有了。this
另外,其實這些說明官方都有提供,這裏也就是把英文譯成了中文,並整理下,加上本身的理解,有問題的地方請各路神仙多多指教。spa
官方文檔在這裏:http://docs.unity3d.com/ScriptReference/EventSystems.EventSystem.html.net
2、UGUI中的事件系統3d
根據第一節中的說明,EventSystem和BaseInputModule是粘在一個對象上的,這兩個模塊在EventSystem對象上能夠直接看到。那麼,BaseRaycaster模塊呢。。。orm
其實射線檢測,確定是從攝像機發起的,那麼BaseRaycaster模塊也必定和攝像機關係必定不簡單。 對於UI模塊,在Canvas對象下咱們能夠看到GraphicRaycaster組件。若是Canvas的渲染模式是SceenSpace-Overlay,那麼咱們是看不到Camera組件的。因此應該是GraphicRaycaster會對UI不一樣的渲染模式作特殊處理。 由於有GraphicRaycaster組件的緣由,Canvas上的全部UI對象,均可以接受輸入模塊發出的事件,具體事件的處理在第四節說明。
3、場景對象中使用事件系統
場景中的非UI對象,若是想要接收輸入模塊的事件,同樣的道理,也須要給攝像機掛上一個射線檢測組件。PhysicsRaycaster, Physics2Draycaster這兩個組件分別是用於3D和2D的場景。固然,還須要場景的對象掛了collider射線才檢測的到。
其實官方對射線檢測也是作了說明的,若是不詳讀手冊是不會發現的,這裏是傳送門:
http://docs.unity3d.com/Manual/Raycasters.html
若是場景中只有一個射線檢測源:When a Raycaster is present and enabled in the scene it will be used by the EventSystem whenever a query is issued from an InputModule.
若是場景中有多個射線檢測源:If multiple Raycasters are used then they will all have casting happen against them and the results will be sorted based on distance to the elements.
4、響應事件
一、輸入模塊能夠檢測到的事件
StandaloneInputModule和TouchInputModule兩個組件會檢測一些輸入操做,以事件的方式(message系統)通知目標對象,那麼這兩個組件支持的事件主要有如下:
[csharp] view plain copy
- IPointerEnterHandler - OnPointerEnter - Called when a pointer enters the object
- IPointerExitHandler - OnPointerExit - Called when a pointer exits the object
- IPointerDownHandler - OnPointerDown - Called when a pointer is pressed on the object
- IPointerUpHandler - OnPointerUp - Called when a pointer is released (called on the original the pressed object)
- IPointerClickHandler - OnPointerClick - Called when a pointer is pressed and released on the same object
- IInitializePotentialDragHandler - OnInitializePotentialDrag - Called when a drag target is found, can be used to initialise values
- IBeginDragHandler - OnBeginDrag - Called on the drag object when dragging is about to begin
- IDragHandler - OnDrag - Called on the drag object when a drag is happening
- IEndDragHandler - OnEndDrag - Called on the drag object when a drag finishes
- IDropHandler - OnDrop - Called on the object where a drag finishes
- IScrollHandler - OnScroll - Called when a mouse wheel scrolls
- IUpdateSelectedHandler - OnUpdateSelected - Called on the selected object each tick
- ISelectHandler - OnSelect - Called when the object becomes the selected object
- IDeselectHandler - OnDeselect - Called on the selected object becomes deselected
- IMoveHandler - OnMove - Called when a move event occurs (left, right, up, down, ect)
- ISubmitHandler - OnSubmit - Called when the submit button is pressed
- ICancelHandler - OnCancel - Called when the cancel button is pressed
只要目標對象的mono腳本實現了以上接口,那麼輸入模塊會將檢測到的事件經過這些接口通知給目標對象。參考:http://docs.unity3d.com/Manual/SupportedEvents.html若是你自定義了本身的輸入模塊,那麼以上這些事件確定是不能用的了。
二、接收輸入事件的方式
1)、自行繼承接口實現監聽
在mono腳本中繼承輸入模塊提供的事件接口,以下圖。接口的定義方式也能夠查下官方手冊,http://docs.unity3d.com/ScriptReference/EventSystems.IBeginDragHandler.html 這邊有每個接口的定義方式,放心大膽地點進去。另外,添加ObjChooseEvent組件的對象,必定要有Collider哦。
[csharp] view plain copy
- public class ObjChooseEvent:MonoBehaviour,IPointerDownHandler,IPointerUpHandler,ISelectHandler,IPointerClickHandler
- {
- private EventSystem currEvent;
- void Start()
- {
- currEvent = EventSystem.current;
- }
- void Update()
- {
-
- }
- public void OnPointerDown(PointerEventData data)
- {
- print("OnPointerDown..");
- currEvent.SetSelectedGameObject(gameObject);
- }
- public void OnPointerUp(PointerEventData data)
- {
- print("OnPointerUp..");
- }
- }
2)、 經過EventTrigger組件監聽事件
這是一個官方組件。在須要監聽事件的對象上,掛上這個組件,而後在Inspector面板展開配置,你會看到這個組件提供了全部輸入模塊支持的事件類型的監聽,以下圖。
![](http://static.javashuo.com/static/loading.gif)
這種方式的優勢是,當你選中一個你要監聽的類型,你能夠爲這個事件類型添加多個監聽接口,統一管理,能夠清楚的知道到底哪些地方響應了這個事件呢。若是是繼承Interface的方式,它將會分散在N個腳本里,一旦出現問題,那查起來必定會很酸爽。
可是這種經過配置的方式,一旦項目多人協做,項目的複雜度起來,這種拖來拽去的配置終究是會有不少問題的,好比某個組件刪除,好比響應接口改了個名字~~都會致使配置丟失,而問題又不能及時發現。又或者程序的監聽接口由於某些條件而不一樣。因此也許你會須要第三種方式。
3)、動態添加EventTrigger組件或者修改組件
程序動態設置實現。咱們在平常的開發中,可能須要動態的變動綁定的事件,那麼咱們如何才能使用C#代碼控制綁定觸發事件呢?下面咱們就介紹代碼控制。ScriptControll.cs腳本。
[csharp] view plain copy
- <span style="font-size:18px;">using UnityEngine;
- using System.Collections.Generic;
- using UnityEngine.Events;
- using UnityEngine.EventSystems;
-
- public class ScriptControl : MonoBehaviour {
- // Use this for initialization
- void Start () {
- EventTrigger trigger = transform.gameObject.GetComponent<EventTrigger>();
- if (trigger == null) trigger = transform.gameObject.AddComponent<EventTrigger>();
- //實例化delegates
- trigger.triggers = new List<EventTrigger.Entry>();
- //定義所要綁定的事件類型
- EventTrigger.Entry entry = new EventTrigger.Entry();
- //設置事件類型
- entry.eventID = EventTriggerType.PointerClick;
- //設置回調函數
- entry.callback = new EventTrigger.TriggerEvent();
- UnityAction<BaseEventData> callback = new UnityAction<BaseEventData>(OnScriptControll);
- entry.callback.AddListener(callback);
- //添加事件觸發記錄到GameObject的事件觸發組件
- trigger.triggers.Add(entry);
- }
- void Update()
- {
- }
- public void OnScriptControll(BaseEventData arg0)
- {
- Debug.Log("Test Click");
- }
- }</span>
其實http://www.cnblogs.com/zou90512/p/3995932.html 這位同窗的博客對這三種方法都作了很詳細的說明。 只不過EventTrigger對外提供的接口不是很友好,致使咱們須要添加一個監聽,彷彿繞了N了山路彎彎,看着就心情不愉快……反而是這位博主後面說的Button的Click事件的實現方式有點意思……若是項目有須要,也許咱們也能夠這麼作……
5、EventSystem組件提供的一些有意思的接口
其實文檔都有http://docs.Unity3D.com/ScriptReference/EventSystems.EventSystem.html 只是也許你沒有注意。 變量:
[csharp] view plain copy
- <span style="font-size:18px;">firstSelectedGameObject:這個值能夠在面板設置,若是你須要遊戲在啓動的時候自動選中某個對象,須要鼠標的那一下點擊。
- currentSelectedGameObject:當前選中的對象,你能夠經過這個值判斷當前是否鼠標點擊在對象上,由於也許你有拖動攝像機的
- 功能,可是你又不喜歡點擊某些對象的時候這個功能又被響應,因此經過這個變量判斷是一個很好的辦法。</span>
接口:
[csharp] view plain copy
- <span style="font-size:18px;">IsPointerOverGameObject:當前鼠標是否在事件系統能夠檢測的對象上。
- SetSelectedGameObject:這個接口也許你會忽略,可是它很棒。由於你點擊場景對象的時候,若是不調用這個接口,你的對象是
- 收不到OnSelect事件的,currentSelectedGameObject的值也不會被設置的,必須在點擊事件裏調用這個接口設置選中對象!</span>
[csharp] view plain copy
- <span style="font-size:18px;">Ex:
- public void OnPointerClick(PointerEventData eventData)
- {
- print ("OnPointerClick...");
- currEvent.SetSelectedGameObject(gameObject);
- }</span>
不用在場景裏找EventSystem對象,EventSystem組件有一個current靜態變量,它就是你要的對象,直接EventSystem.current便可使用。