序言:
關於UnityUGUI系統還是挺複雜,這裏記錄一下平常遇到的問題。
正文:
UI世界座標系和屏幕座標系的統一
接觸過U3D的同學都知道當我們在項目中新建UI對象時,都會在創建在名爲Canvas的對象下,如下圖
這幾天在工作中遇到一個問題,就是 UI跟隨鼠標運動,本來使用的是以下程序:
var x = Mathf.Clamp(Input.mousePosition.x, 0, Screen.width);
var y = Mathf.Clamp(Input.mousePosition.y, 0, Screen.height);
transform.position = new Vector3(x, y, 0);
後來更新代碼想到Input.mousePosition是屏幕座標,而transform.position是世界座標系,我這樣直接賦值會不會發生座標錯誤。後來發現其實系統爲我們創建的Canvas其實已經自動完成了UI世界座標系和屏幕座標系的轉換。
當我在Game視圖下改變屏幕大小時,我發現Canvas的長寬始終是固定的,隨着屏幕實際尺寸變化的是Scale屬性。並且我嘗試在Game視圖下改變屏幕大小時,打印出Canvas的實際尺寸和屏幕的實際尺寸:
void Update()
{
var canvas = GameObject.Find("Canvas").GetComponent<RectTransform>();
Debug.Log("屏幕尺寸:"+Screen.width+" "+Screen.height+";"+
"Canvas尺寸: "+canvas.rect.width*canvas.localScale.x+" "+
canvas.rect.height * canvas.localScale.y);
}
可以看出,無論我如何改變Game窗口的大小,Canvas的實際尺寸和屏幕的實際大小都是一致的。說明Unity在Canvas這裏幫我們完成了屏幕座標系和UI世界座標系的轉換。
UGUI Button的交互
Unity UGUI點擊響應的必要條件是至少本身或者子對象有Graphic子類組件處於激活狀態並且Raycast Target屬性爲真,而且需要獲取事件對象的子對象會獲取事件並將事件傳遞給父對象。
測試:
首先,我們在項目中新建三個Image對象,並分別命名爲Button、Child、Other,爲Button對象添加Button組件,將Child設置爲Button的子對象,並讓Other大小與Button大小一致,並正好擋在Button的前面。爲了後期觀察分別將三個對象設置爲白色、黑色、半透明白色。
button.onClick.AddListener(delegate { Debug.Log("Click"); });
屬性設置:
|
激活 |
Image激活 |
Raycast Target |
Button |
true |
true |
true |
Child |
true |
true |
true |
Other |
true |
true |
true |
結果:
證明與Button處於兄弟節點關係,層級在Button對象之前且RaycastTarget屬性爲真的對象會擋住Button獲取點擊事件。
屬性設置:
|
激活 |
Image激活 |
Raycast Target |
Button |
true |
true |
true |
Child |
true |
true |
true |
Other |
true |
true |
false |
結果:
證明RaycastTarget屬性爲真對象會截獲點擊事件並組織事件向下傳遞。
屬性設置:
|
激活 |
Image激活 |
Raycast Target |
Button |
true |
true |
true |
Child |
true |
true |
true |
Other |
true |
false |
true |
結果:
證明UI對象獲取事件依賴於Graphic類組件,並且Button子對象並不會截取父對象的時間獲取。
屬性設置:
|
激活 |
Image激活 |
Raycast Target |
Button |
true |
false |
true |
Child |
true |
true |
true |
Other |
false |
true |
true |
結果:
點擊在Child對象渲染區域上仍舊會有事件響應,說明子對象會幫助父對象獲取事件並將事件傳遞給父對象。
綜上,Unity UGUI點擊響應的必要條件是至少本身或者子對象有Graphic子類組件處於激活狀態並且Raycast Target屬性爲真,而且需要獲取事件對象的子對象會獲取事件並將事件傳遞給父對象。