【轉】NGUI 按鈕觸發事件原理解析

一般咱們爲對象附加一個腳本組件,腳本組件只要加此鼠標處理事件方法,這個對象就有了點擊事件了:


void OnClick() { Debug.Log("onclick"); }
可爲何我只要給一個對象附加個腳本,腳本中寫此OnClick方法,當咱們點擊按鈕時他就會去執行OnClick方法呢?unity是怎麼把他們聯繫起來的呢?還有除了OnClick事件,還有沒有其餘事件能夠像OnClick事件同樣被咱們使用,例如:OnDoubleClick,OnHover,OnPress等
答案就在UICamera裏面,這個腳本是附在Camera對象上的,有哪些事件咱們能夠用的,UICamera都告訴咱們了,以下:


這些都是你們很經常使用的事件,因此就不一一解釋了!有哪些事件咱們能夠調用,這個問題解決了。 html

接下來看,附加到對象上的腳本中的事件(以上所列出的事件)是如何被執行的?接下來咱們就來看下UICamera是如何對這些事件進行處理的! app

在UICamera裏面最早執行的就是Awake方法,因此咱們先從Awake方法看起: ide

能夠看出Awake方法主要的功能就是判斷設備類型,從而肯定你是使用的是鼠標仍是觸摸方式,但咱們一般都是用電腦去設計遊戲,因此以上的判斷都沒有被執行,而useMouse和useTouch字段默認都爲true,因此這兩個字段的值不變,接下來看Update方法(Start方法沒什麼好說的),當執行到update中的一段代碼時,以下: ui


// Process touch events first 
if (useTouch) ProcessTouches(); 
else if (useMouse) ProcessMouse();


由於useTouch爲true,因此程序回去執行 ProcessTouches方法,這個方法主要是對觸屏事件方法的響應,轉到ProcessTouches方法,運行到這句話:for (int i = 0; i < Input.touchCount; ++i),這句話Input.touchCount爲0,由於咱們操做電腦只能經過鼠標,根本不存在觸屏操做,因此Input.touchCount爲0,程序繼續執行下面的 spa


複製代碼
if (Input.touchCount == 0) { 
    if (useMouse) ProcessMouse(); 
    #if UNITY_EDITOR 
    else ProcessFakeTouches(); 
    #endif 
}
複製代碼


若是沒有觸屏事件,那麼就會去執行鼠標事件,也就是去執行ProcessMouse方法去,轉到ProcessMouse方法,裏面有這麼一段代碼: 設計


複製代碼
 bool isPressed = false
bool justPressed = false
for (int i = 0; i < 3; ++i) { 
    if (Input.GetMouseButtonDown(i)) { currentScheme = ControlScheme.Mouse; justPressed = true; isPressed = true; } 
    else if (Input.GetMouseButton(i)) { currentScheme = ControlScheme.Mouse; isPressed = true; } } 
// No need to perform raycasts every frame 
if (isPressed || posChanged || mNextRaycast < RealTime.time) { mNextRaycast = RealTime.time + 0.02f
    if (!Raycast(Input.mousePosition)) hoveredObject = fallThrough; 
    if (hoveredObject == null) hoveredObject = genericEventHandler; 
    for (int i = 0; i < 3; ++i) mMouse[i].current = hoveredObject; }
複製代碼


當咱們點擊按鈕時,isPressed就會爲true,而mNextRaycast 永遠<RealTime.time,因此內部的代碼一直會被執行,也就是說一直執行裏面的Raycast方法(即咱們所知的發射線),轉到Raycast方法去,在Raycast方法裏面,他會判斷你當前選擇的EventType,有兩種選擇:World 表示按被擊中點的距離排序執行一個物理射線,UI表示按部件深度排序執行一個物理射線,一般咱們選擇的是UI,由於對象的層次咱們一般是按depth來設計的,在 i f (cam.eventType == EventType.UI) 裏面他會執行Physics.RaycastAll ,也就是發出射線,並把擊中的對象賦給hoveredObject(hoveredObject = hit.collider.gameObject),RayCast的做用差很少就是找到被擊中的對象,賦給hoveredObject,回過頭來,由於hoveredObject對象保存的是被擊中的對象,在ProcessMouse方法裏for (int i = 0; i < 3; ++i) mMouse[i].current = hoveredObject;把此對象付給了mMouse[i],for循環之因此爲3次,由於鼠標有三個鍵,左鍵,滾輪鍵,右鍵,代碼繼續執行 code


複製代碼
// Process all 3 mouse buttons as individual touches 
for (int i = 0; i < 3; ++i) {
    bool pressed = Input.GetMouseButtonDown(i); 
    bool unpressed = Input.GetMouseButtonUp(i); 
    if (pressed || unpressed) currentScheme = ControlScheme.Mouse; currentTouch = mMouse[i]; currentTouchID = -1 - i; currentKey = KeyCode.Mouse0 + i; 
    if (pressed || unpressed) 
    // We don't want to update the last camera while there is a touch happening 
        if (pressed) currentTouch.pressedCam = currentCamera; 
        else if (currentTouch.pressed != null) currentCamera = currentTouch.pressedCam; 
    // Process the mouse events  
    ProcessTouch(pressed, unpressed); currentKey = KeyCode.None;
}
複製代碼


這裏能夠看到,射線擊中的對象被賦給了currentTouch對象了,當鼠標按下時,pressed表示是否按下,unpressed表示鼠標是否擡起,當咱們點擊按鈕知道完成,pressed和unpressed值會經歷這樣的變化:True,false -> false true,程序執行到ProcessTouch方法,由於咱們是點擊事件,因此此方法內部的Notify(currentTouch.pressed, "OnClick", null)這段代碼會被執行,繼續執行Notify方法: orm


複製代碼
static public void Notify(GameObject go, string funcName, object obj) { 
    if (mNotifying) return; mNotifying = true
    if (NGUITools.GetActive(go)) { go.SendMessage(funcName, obj, SendMessageOptions.DontRequireReceiver); 
       if (genericEventHandler != null && genericEventHandler != go) { genericEventHandler.SendMessage(funcName, obj, SendMessageOptions.DontRequireReceiver); } } mNotifying = false; }
複製代碼


內部是調用對象的SendMessage方法的,對SendMessage方法不懂得,能夠參照這篇文章: htm

http://www.cnblogs.com/MrZivChu/p/sendmessage.html 對象

就此就完成了整個onclick方法的執行了,由於Update方法是一直執行的,因此UICamera腳本會一直髮出射線來檢測鼠標或者觸屏事件,從而執行相應的方法,原理大概就是這樣!

相關文章
相關標籤/搜索