newGUI 中如何判断鼠标在某个控件范围内?

newGUI 中如何判断鼠标在某个控件范围内?(AB两种方法)

A.通过数学计算

根据 Canvas 的 RenderMode 不同分为两种情况:

1、Screen Space - Overlay(2D游戏或普通APP)

public Rect GetSpaceRect(RectTransform rect)
{
	Rect spaceRect = rect.rect;
	Vector3 spacePos = rect.position;
	spaceRect.x = spaceRect.x * rect.lossyScale.x + spacePos.x;
	spaceRect.y = spaceRect.y * rect.lossyScale.y + spacePos.y;
	spaceRect.width = spaceRect.width * rect.lossyScale.x;
	spaceRect.height = spaceRect.height * rect.lossyScale.y;
	return spaceRect;
}
Rect rt = GetSpaceRect( rawImage.rectTrasform)
if( rt.Contains(Input.mousePosition))
{
   //dos omething
}

研究了下 Screen space - Overlay下的计算原理:
在overlay模式下,不需要uicamera,所有UIBehaviour子类直接使用一个构造好的 orthogonal projection matrix,
等同于一个UICamera,其Size为 Screen.Height * 0.5f ,Projection为Orthographic,Clipping Planes为正无穷和负无穷。
再加上CanvasScaler的计算,在公式上直接让所有对象的 world position 等于 screen position。
变换路径为:【ui space -> world space -> viewport space -> screen space】

2、Screen Space - Camera(绝大多数3D游戏或多uicamera的APP使用)

var mg = gameObject.GetComponent<MaskableGraphic> ();
var rectTransform = mg.rectTransform;
Camera uicamera = Camera.main; // 此处按需取uicamera,不一定是main.
Debug.Log ("in:" + RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Input.mousePosition, uicamera));

研究了下 RectangleContainsScreenPoint 原理:
1、具有 CanvasScaler脚本的Canvas的GameObject的position坐标是相对于UICamera 的 World Space Position(一般为0,0,0)。这个Canvas认为是【RootCanvas】
2、RootCanvas 的所有子对象,其localPosition为 UI Resolution 下的坐标(比如 1920*1080) , 称为 【UI Space Local Position】,这个变换由 CanvasScaler 计算得出,并通过修改 RootCanvas 的scale值来应用变换。
3、子对象的RectTransform.rect是 UI Spcae 下的 rect
4、变换路径是 【(uispace) ui local position to ui world position(级联计算 ui position)】-> 【uispace -> world space ref uicamera】-> 【world space - >  viewport space -> screen space】
5、手动计算如下:
var mg = gameObject.GetComponent<MaskableGraphic> ();
var rect = mg.rectTransform.rect;

Camera uicamera = Camera.main;

Vector3 screen_to_ui_scale = mg.rectTransform.lossyScale;
float uix = rect.x + mg.rectTransform.localPosition.x;
float uicamera_world_x = uix * screen_to_ui_scale.x;

float uiy = rect.y + mg.rectTransform.localPosition.y;
float uicamera_world_y = uiy * screen_to_ui_scale.y;

float uixm = uix + rect.width;
float uicamera_world_w = uixm * screen_to_ui_scale.x;

float uiym = uiy + rect.height;
float uicamera_world_h = uiym * screen_to_ui_scale.y;

Vector2 min = uicamera.WorldToScreenPoint (new Vector3 (uicamera_world_x, uicamera_world_y));
Vector2 max = uicamera.WorldToScreenPoint (new Vector3 (uicamera_world_w, uicamera_world_h));
Rect rect_screen = new Rect (min, (max - min));

Debug.Log ("In:" + rect_screen.Contains (Input.mousePosition));


B.通过EventSystem

var trigger = gameObject.AddComponent<UnityEngine.EventSystems.EventTrigger> ();
var entry = new UnityEngine.EventSystems.EventTrigger.Entry ();
entry.eventID = UnityEngine.EventSystems.EventTriggerType.PointerEnter;
entry.callback.AddListener( (data) =>
{
	Debug.Log ("Input.mousePosition:"+Input.mousePosition);
});
trigger.triggers.Add (entry);

EventSystem本质上也是做计算,而且还走了很多结构性代码,所以如果如果可以用数学解决的话,就不要用回调函数来解决.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值