unity给我们提供了一条api。
EventSystem.current.IsPointerOverGameObject()==true
他是利用unity的EventSystem事件系统判断射线是否射到物体上。我们查看官方文档可以看到继承BaseRaycaster的有三个组件,.PhysicsRaycaster, Physics2DRaycaster, GraphicRaycaster,所以当我们项目中只有canvas自带的GraphicRaycaster时,我们可以使用上述api判断鼠标是否在UI上。但是当我们场景camera上挂有PhysicsRaycaster,则判断完全会出现问题。我们会发现鼠标移动到含有collider的3D物体上以上API也会返回true。此时我们需要自己写一个射线检测的方法来判断是否在UI上。
我们可以将方法写在静态工具类里供全局调用。
static List<GraphicRaycaster> graphicRays;
private static List<GraphicRaycaster> graphicRaycasters
{
get
{
if(graphicRays == null)
{
graphicRays = GameObject.FindObjectsOfType<GraphicRaycaster>().ToList<GraphicRaycaster>();
}
return graphicRays;
}
}
private static EventSystem eventSystem
{
get { return EventSystem.current; }
}
/// <summary>
/// 是否在UI上
/// </summary>
/// <returns></returns>
public static bool IsOnUIElement()
{
eventData = new PointerEventData(eventSystem);
eventData.pressPosition = Input.mousePosition;
eventData.position = Input.mousePosition;
List<RaycastResult> list = new List<RaycastResult>();
if (graphicRaycasters == null) return false;
foreach (var graphicRaycaster in graphicRaycasters)
{
graphicRaycaster.Raycast(eventData, list);
foreach (var temp in list)
{
if (temp.gameObject.layer.Equals(5)) return true;
}
}
return false;
}
注意这里要获取所有的canvas上的GraphicRaycaster。另外:当我们要动态生成新的canvas添加到场景时,我们要写一个方法来管理新增的canvas上绑定的GraphicRaycaster。每个canvas上的GraphicRaycaster只能检测到目录下的UI.一般出现在动态生成3D canvas情景。
/// <summary>
/// 增加新的GraphicRaycaster
/// </summary>
/// <param name="item"></param>
public void AddGraphicRaycaster(GraphicRaycaster item)
{
graphicRays.Add(item);
}
/// <summary>
/// 移除GraphicRaycaster
/// </summary>
/// <param name="item"></param>
public void RemoveGraphicRaycaster(GraphicRaycaster item)
{
if (graphicRays.Contains(item))
graphicRays.Remove(item);
}