处理UI还有3D模型的点击推荐使用UGUI的这套事件系统,因为使用起来比较简洁,不需要自己用代码来发送射线,并且可以很好的处理同时点击UI和3D模型上。
1.给3D摄像机挂一个Physics Raycaster组件。Event Mask过滤掉UI.
2.用unity自带的Event Trigger 或者 http://www.xuanyusong.com/archives/3325 就可以对UI 或者 3D模型进行点击事件的监听了
3.OK 当UI与模型相互叠加的时候,优先响应UI,并且响应最前面的UI.
4.如下图所示,前面是UI后面是3D模型,被挡住的模型或者UI是不会被响应的。
假如想把点击的事件透下去,让所有的UI或者模型都能正确的响应事件,怎么办呢?
代码: 把这段脚本挂在最前面的UI上。 然后当接收到点击事件后,调用PassEvent把当前的事件透下去。由于UGUI的事件有很多种,比如点击 、抬起、拖动、落下、第二个参数就是ExecuteEvents.Handler 把对应的Handler传进去就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
using UnityEngine; using System.Collections; using UnityEngine.EventSystems; using UnityEngine.UI; using System.Collections.Generic; public class Test : MonoBehaviour,IPointerClickHandler ,IPointerDownHandler,IPointerUpHandler { //监听按下 public void OnPointerDown(PointerEventData eventData) { PassEvent(eventData,ExecuteEvents.pointerDownHandler); } //监听抬起 public void OnPointerUp(PointerEventData eventData) { PassEvent(eventData,ExecuteEvents.pointerUpHandler); } //监听点击 public void OnPointerClick(PointerEventData eventData) { PassEvent(eventData,ExecuteEvents.submitHandler); PassEvent(eventData,ExecuteEvents.pointerClickHandler); } //把事件透下去 public void PassEvent<T>(PointerEventData data,ExecuteEvents.EventFunction<T> function) where T : IEventSystemHandler { List<RaycastResult> results = new List<RaycastResult>(); EventSystem.current.RaycastAll(data, results); GameObject current = data.pointerCurrentRaycast.gameObject ; for(int i =0; i< results.Count;i++) { if(current!= results[i].gameObject) { ExecuteEvents.Execute(results[i].gameObject, data,function); //RaycastAll后ugui会自己排序,如果你只想响应透下去的最近的一个响应,这里ExecuteEvents.Execute后直接break就行。 } } } } |
这样UI下面那些对应接收点击事件的地方都可以响应到了。。如下图所示,我点击在前面的UI后面的消息也能响应到了。
- 本文固定链接: https://www.xuanyusong.com/archives/4241
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!
雨松大大为什么,下面的按钮注册的方法会响应两次啊
大神我是U5.6.2版本的也会栈溢出,我把按下和抬起注释了,虽然不报溢出了,但是unity直接卡死了。。。
请教一下,能不能让外部导入的模型,也能有这个监听点击的能力呀,测试了出了ugui的物体,其他的都不能被点击到
unity5.5.2f1版本,把脚本挂在UI上,一点Unity就挂了,报错“堆栈溢出”
如果两个都挂了这个脚本的,在重叠区域好像会出现堆栈很深的问题,在RaycastAll之前加个标志位,表示这个事件已经透传过,如果传回到自己,就忽略掉,然后在透传结束,将标志位设置回来
if(hasPassedEvent)
{
return;
}
hasPassedEvent = true;
List results = new List();
EventSystem.current.RaycastAll(data, results);
GameObject current = gameObject;
for (int i = 0; i < results.Count; i++)
{
if (current != results[i].gameObject)
{
if(ExecuteEvents.Execute(results[i].gameObject, data, function))
{
break;
}
//RaycastAll后ugui会自己排序,如果你只想响应透下去的最近的一个响应,这里ExecuteEvents.Execute后直接break就行。
}
}
results.Clear();
hasPassedEvent = false;
你这个标记法6炸了,上面确实容易导致堆栈溢出,陷入一个死循环把Unity卡死。
厉害了,确实容易卡死…
不是吧, 我测试了一下没有啊, 你说的是PC上的hightlight状态吧?
我有一个小疑问,希望雨松大神解惑:在MonoBehaviour 里,有一组OnMouseEnter, OnMouseDown, OnMouseUp 方法,将写有这些方法的脚本挂在3d空间里的Mesh上,也可以检测到S是否被鼠标点击或移入的事件。如果如大神所说,建议3d的game object 也使用 UGUI的这套事件系统来做事件监听, 那么这套系统相比之前我提到的Monobehaviour里的内置方法,有什么优势?望大神指点。
OnMouseEnter 这个在手机上用不了。。
是的,但是OnMouseDown 和 OnMouseUp 是可以的。
这个会造成内存泄漏,能帮看看吗?头疼死了。IEnumerator GoDownLoadStart(){//Resources.UnloadUnusedAssets();Debug.Log (“开始下载器2” url);WWW www = new WWW (url);while (!www.isDone) {Debug.Log (string.Format(“下载中:{0}”,www.progress));yield return null;}if (www.error != null) {Debug.Log (“下载错误:” http://www.error);}else {File.WriteAllBytes(path,www.bytes);Debug.Log (“下载完成,大小:” http://www.bytesDownloaded “字节”);}Debug.Log (“清除镜像”);www.assetBundle.Unload (false);Debug.Log (“清除垃圾”);www.Dispose ();Debug.Log (“清除未引用”);www = null;Debug.Log (“www=null”);Resources.UnloadUnusedAssets();Debug.Log (“清除GC”);GC.Collect ();Destroy (this.gameObject);}
这个会造成内存泄漏,能帮看看吗?头疼死了。IEnumerator GoDownLoadStart() { //Resources.UnloadUnusedAssets(); Debug.Log (“开始下载器2″+url); WWW www = new WWW (url); while (!www.isDone) { Debug.Log (string.Format(“下载中:{0}”,www.progress)); yield return null; } if (www.error != null) { Debug.Log (“下载错误:”+www.error); } else { File.WriteAllBytes(path,www.bytes); Debug.Log (“下载完成,大小:” + http://www.bytesDownloaded+ “字节”); } Debug.Log (“清除镜像”); http://www.assetBundle.Unload (false); Debug.Log (“清除垃圾”); http://www.Dispose (); Debug.Log (“清除未引用”); www = null; Debug.Log (“www=null”); Resources.UnloadUnusedAssets(); Debug.Log (“清除GC”); GC.Collect (); Destroy (this.gameObject); }
雨凇大大,我用ugui构建完ui系统后,当用鼠标点击其中一个button后,在按下键盘的方向键,就会对ui中的button进行选择,如何解决这个bug啊?
这不是bug啊。在EventSystem上不要勾选send navigation evetns就可以了
谢谢雨凇大大,确实如此
666