unityunity3d ugui buttonn 怎么左方向

Unity UGUI ---- 鼠标穿透UI问题(Unity官方的解决方法)
最近在用UGUI的时候遇到了鼠标穿透的问题,就是说在UGUI和3D场景混合的情况下,点击UI区域同时也会 触发3D中物体的鼠标事件。比如下图中
这里给Cube加了一个鼠标点击改变颜色的代码,如下
void Update()
if(Input.GetMouseButtonDown(0))
GetComponent&Renderer&().material.color = new Color(Random.value, Random.value, Random.value, 1.0f);
运行一下,会发现只要有鼠标点击(任何位置点击),Cube的颜色就会改变,根据代码我们知道这也是必然的,但是问题是如果Cube是一个3D世界中的mesh或者terrain,而button是UI的话也同样会出现同样的问题。
在游戏开发中我们的UI是始终出现在屏幕的,如果在一个战斗场景中用户点了UI战斗场景中的物体也会作出响应肯定是有问题的!
其实关于这个问题网上有不少解决方法了,但是总感觉没有一个是适合我的需求,或者说没有一个最好的***。
其中提到最多的是利用EventSystem.current.IsPointerOverGameObject()来判断,这个方法的意义是判断鼠标是否点到了GameObject上面,这个GameObject包括UI也包括3D世界中的任何物体,所以他只能判断用户是都点到了东西。对于本文中的问题意义不是很大。那么这个问题到底该怎么解决呢?
解决方法最终还是离不开射线检测,不过UGUI中已经封装了针对UI部分的射线碰撞的功能,那就是GraphicRaycaster类。里面有个Raycast方法如下,最终就是将射线碰撞到的点添加进resultAppendList数组。
public override void Raycast(PointerEventData eventData, List&RaycastResult& resultAppendList)
if (canvas == null)
// Convert to view space
if (eventCamera == null)
pos = new Vector2(eventData.position.x / Screen.width, eventData.position.y / Screen.height);
pos = eventCamera.ScreenToViewportPoint(eventData.position);
// If it's outside the camera's viewport, do nothing
if (pos.x & 0f
pos.x & 1f
pos.y & 0f
pos.y & 1f)
float hitDistance = float.MaxV
Ray ray = new Ray();
if (eventCamera != null)
ray = eventCamera.ScreenPointToRay(eventData.position);
if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None)
float dist = eventCamera.farClipPlane - eventCamera.nearClipP
if (blockingObjects == BlockingObjects.ThreeD
blockingObjects == BlockingObjects.All)
if (Physics.Raycast(ray, out hit, dist, m_BlockingMask))
hitDistance = hit.
if (blockingObjects == BlockingObjects.TwoD
blockingObjects == BlockingObjects.All)
RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, dist, m_BlockingMask);
if (hit.collider != null)
hitDistance = hit.fraction *
m_RaycastResults.Clear();
Raycast(canvas, eventCamera, eventData.position, m_RaycastResults);
for (var index = 0; index & m_RaycastResults.C index++)
var go = m_RaycastResults[index].gameO
bool appendGraphic = true;
if (ignoreReversedGraphics)
if (eventCamera == null)
// If we dont have a camera we know that we should always be facing forward
var dir = go.transform.rotation * Vector3.
appendGraphic = Vector3.Dot(Vector3.forward, dir) & 0;
// If we have a camera compare the direction against the cameras forward.
var cameraFoward = eventCamera.transform.rotation * Vector3.
var dir = go.transform.rotation * Vector3.
appendGraphic = Vector3.Dot(cameraFoward, dir) & 0;
if (appendGraphic)
float distance = 0;
if (eventCamera == null
canvas.renderMode == RenderMode.ScreenSpaceOverlay)
distance = 0;
// /a06-_intersect-2.html
distance = (Vector3.Dot(go.transform.forward, go.transform.position - ray.origin) / Vector3.Dot(go.transform.forward, ray.direction));
// Check to see if the go is behind the camera.
if (distance & 0)
if (distance &= hitDistance)
var castResult = new RaycastResult
gameObject = go,
module = this,
distance = distance,
index = resultAppendList.Count,
depth = m_RaycastResults[index].depth,
sortingLayer =
canvas.sortingLayerID,
sortingOrder = canvas.sortingOrder
resultAppendList.Add(castResult);
从这个方法开始深入查看Unity UGUI源码你会发现,其实每个组件在创建的时候已经被添加进了一个公共列表,UGUI 源码中的GraphicRegistry类就是专门干这件事的。再看下Graphic类中的OnEnable方法
protected override void OnEnable()
base.OnEnable();
CacheCanvas();
GraphicRegistry.RegisterGraphicForCanvas(canvas, this);
#if UNITY_EDITOR
GraphicRebuildTracker.TrackGraphic(this);
if (s_WhiteTexture == null)
s_WhiteTexture = Texture2D.whiteT
SetAllDirty();
SendGraphicEnabledDisabled();
看这句GraphicRegistry.RegisterGraphicForCanvas(canvas, this);就是注册需要做射线检测的UI组件。再看他内部是如何工作的
public static void RegisterGraphicForCanvas(Canvas c, Graphic graphic)
if (c == null)
IndexedSet&Graphic&
instance.m_Graphics.TryGetValue(c, out graphics);
if (graphics != null)
graphics.Add(graphic);
graphics = new IndexedSet&Graphic&();
graphics.Add(graphic);
instance.m_Graphics.Add(c, graphics);
不过,问题又来了,为什么是添加进列表的对象都是Graphic类型呢?这跟ScrollRect,Button,Slider这些有关吗?其实,这就跟UGUI的类继承关系有关了,其实我们使用的UGUI中的每个组件都是继承自Graphic或者依赖一个继承自Graphic的组件
看一下UGUI的类层次结构就会一目了然,如下
看图就会更加清楚,在这我们可以把我们用到的UGUI的所有组件分为两类,1.是直接继承自Graphic的组件。2.是依赖于1的组件"[RequireComponent(typeof(Griphic))]",仔细想想会发现,所有组件都属于这两种中的某一种。
所以对所有Graphic进行Raycast其实就相当于对所有UI组件进行Raycast。
结合上面的知识所以,解决这个问题最好的方法是根据,UGUI的射线碰撞来做。这样会比较合理。
这里我们直接在使用Input.GetMouseButtonDown(0)的地方加了一个检测函数,CheckGuiRaycastObjects,如下
bool CheckGuiRaycastObjects()
PointerEventData eventData = new PointerEventData(Main.Instance.eventSystem);
eventData.pressPosition = Input.mouseP
eventData.position = Input.mouseP
List&RaycastResult& list = new List&RaycastResult&();
Main.Instance.graphicRaycaster.Raycast(eventData, list);
//Debug.Log(list.Count);
return list.Count & 0;
不过在使用时需要先获取两个加粗显示的变量,graphicRaycaster和eventSystem。
这两个变量分别对应的是Canvas中的GraphicRaycaster组件,和创建UI时自动生成的&EventSystem&中的EventSystem组件,用的是自己制定以下就可以。
然后在使用的时候可以这样:
void Update ()
if (CheckGuiRaycastObjects()) return;
//Debug.Log(EventSystem.current.gameObject.name);
if (Input.GetMouseButtonDown(0))
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
//do some thing
还有一个需要注意的地方就是,在做UI的时候一般会用一个Panel做跟目录,这个panel也会被添加到GraphicRegistry中的公共列表中,如果是这样的话记得把list.Count&0改成list.Count&1,或者直接删除Panel上的继承自Graphic的组件。
这样在结合着EventSystem.current.IsPointerOverGameObject()来使用就比较好了。
本文固定连接:/fly-100/p/4570366.html
ok了,现在舒服多啦!
> 本站内容系网友提交或本网编辑转载,其目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请及时与本网联系,我们将在第一时间删除内容!
项目制作过程中,我们往往会引入一些SDK来实现Unity引擎本身无法实现的功能,在关于安卓这方面,我们都知道安卓包中都有一个叫AndroidManifest.xml的配置文件,当我们引入2个或者多个安卓插件后就会存在插件之间的冲突问题,Unity会自动将它们合并成一个配置文件,可能会导致其中的一个或者多个插件无法正常发挥,甚至会使得工程崩溃.下面我 ...
一个脚本名称为aaaa,如果将脚本名称(外部和内部同时修改)bbbb,拖拽到预制体上,本地运行不会有任何问题,如果将项目上传至SVN或者打包发给其他人使用,有时候会出现预制体上面脚本丢失状况. 解决方法: 不修改aaaa脚本,直接新建脚本bbbbb,然后将aaaa脚本代码到bbbb脚本中,然后删除aaaa脚本,最后将bbbb脚本拖拽到预制体上使用.
主板的键鼠开机功能是造成鼠标在关机后仍然发光的最普遍的原因.主板的BIOS中一般都提供了对键鼠开机功能的设定,大家可以进入BIOS主菜单的 &Power Management Setup&页面找到&S3 KB Wake-Up Function&或者是含义相近的选项,将其设置为&Disable&,关闭 ...
用了快一年的MacBook Pro最近出现了奇怪的问题.出问题时,鼠标不受控制,屏幕上鼠标指针乱窜,还时不时自动点击,犹如电脑被人远程控制一般.不管是用trackpad还是用外接鼠标,都是同样问题.电脑根本无法使用,让人郁闷至极. 前几次出现问题时,关机一段时间后再开机就好了.可是今天出现问题后,无论怎么整,即使关机几小时,问题也依旧. 后来冷静下来仔细分析 ...
由于onmouseout事件在鼠标移到 层里是也会触发,所用一下js解决 调用方法为:hiddensales(this,event) function hiddensales(obj, e) { if (e.currentTarget) {
if (e.relatedTarget != obj) {
if (obj == e.relatedTa ...
JQuery UI autocomplete 的功能,类似于 google 搜索框中自动提示,用于 Web 网页开发中的文本框的自动填充.虽然比另一个类似控件(http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/)简单,但基本功能都有,配合 JQuery UI 可切换网页界面皮肤的辅 ...
在虚拟机VM中***完Fedora8后,提示***VMware Tools,在根据提示***完VMware Tools后结果原来可以用的鼠标滚轮不会动了,不管怎样在什么程序下鼠标滚轮都不能用. 后来经过查找终于发现是VMware Tools修改了 /etc/X11/xorg.conf 文件,在终端中输入 sudo gedit /etc/X11/xorg.conf ...
最近修了一个Bug, 发现在.net 框架下, 消息处理的函数混乱, 导致一些不可预知的错误产生,比如当一个Datagrid view 的cell还在编辑的过程中的时候, 其他的消息处理函数对这个cell 进行了重新写内容的操作,会造成程序的Crash. The exception is &Operation is not valid b ...温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
&1.这个是正常状态,切换并没有问题&2.这个是按钮按下之后的状态,可以发现Highlighted 的状态一直处于true所以鼠标移开并没有发生改变这个解决办法就是在按钮上***鼠标离开区域的事件OnPointerExit 这个事件,如果鼠标离开则设置Highlighted&为falseNormal 为 truevoid OnExit(GameObject go) {
if(anim!= null)
anim.SetBool("Highlighted",false);
anim.SetBool("Normal",true);
} }3.这个可能是我自己设置没对的地方,如果找到更好的解决办法请发我邮箱
阅读(389)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'Unity中UGUI Button动画系统点击之后一直处于Highlighted状态的解决办法',
blogAbstract:'当Button 的动画设置完成之后,如果不点击只是移动到按钮和移开按钮的话一切正常如果按下按钮之后再移开按钮并没有还原到Normal&1.这个是正常状态,切换并没有问题&2.这个是按钮按下之后的状态,可以发现Highlighted 的状态一直处于true所以鼠标移开并没有发生改变这个解决办法就是在按钮上***鼠标离开区域的事件OnPointerExit 这个事件,',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:6,
publishTime:1,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

参考资料

 

随机推荐