ugui源码_关于UGUI中点击判断的原理探究

纵观网络上绝大部分讲到UGUI原理的文章,在谈及点击判断时,都认为是通过射线检测来进行判断的,笔者曾经也对此深信不疑,直到前段时间亲自阅读了UGUI的C#源码,方才发现并非如此,那么UGUI究竟是如何进行点击判断的呢?接下来便由笔者通过对源码的逐步分析来探究这个问题。

f1c382cae941cd6bfa8d060a8c1ce821.png

打开EventSystem类,会看到里面使用一个列表来保存所有BaseInputModule

0c0acea194d7c0c1d422cf73e2a09e71.png

9e618cf5e028930c50e628b8164820f7.png

BaseInputModule是负责检测并处理玩家输入的组件,会在自身OnEnableOnDisable时调用EventSystem.UpdateModels更新列表。

a58c863b7568cd3cbec54fd82c1d3f59.png

EventSystem会在每次Update时,去调用CurrentInputModuleProcess方法进行输入处理。

BaseInputModule有一个子类:StandaloneInputModule,即标准输入模块,是在UGUI事件系统中所默认使用,所以此处可以右键转到StandaloneInputModule类中对Process的实现进行查看。

74579082d801e07e8ae6289d6e6fdd96.png

可以看到这里进行了很多处理,不过在暂时只需要关注ProcessTouchEvents即可。

b85b0c17384e223a9ca0f2d2049cdfdd.png

ProcessTouchEvents中,通过调用input.GetTouch获取到Touch对象(input属性是BaseInput类型的,而BaseInput类又是对Input类的封装)以得到被点击位置的信息。然后通过调用基类PointerInputModuleGetTouchPointerEventData方法获取到PinterEventData对象,最后借助PointerEventData进行各种事件处理。

那么接下来的目标就很明确了,转至GetTouchPointerEventData方法中。

6aae50b2867109b85998f5b97aa1ec60.png

其中又通过调用EventSystem.RaycastAll获取到所有被点击物体,然后找到排第一的来作为此次点击到的物体,让我们转至EventSystem.RaycastAll方法中。

cda8d2a54af99b6d47b180bc7b1b1b74.png

RaycastAll方法中,首先通过RaycasterManager获取到所有BaseRaycaster对象,然后依次调用这些RaycasterRaycast方法获取到被点击的物体。

BaseRaycaster.Raycast这个方法,从命名上看,和Physics上的Raycast一样,那么是否真的是在其中通过射线来检测UI点击的呢?让我们右键转到UI专用的GraphicRaycasterRaycast实现中。

e7d1247faf7aaed94084300fbaf2e317.png

可以看到里面有一长串的代码。

a989c6f064c00e2b45e0e0e67980fe88.png

往下翻,可以看到这里创建了Ray对象,看到这里,或许会有人认为点击判断看来的确是由射线完成的,别急,让我们继续往下翻,看看这个射线被用到了哪里。

eb8069bad2a5e4332659645a5fd64e53.png

可以看出,这个射线对象,是只有要进行遮挡对象检测时,才会被用到的,也就是说这个射线对象是用来检测2D/3D物体对UI的遮挡的,而不是用来检测UI点击的,那么UI点击究竟是如何进行检测的呢?让我们继续往下翻。

80a0ae37365d1106de15afdba3542518.png

此处,调用了另一个Raycast重载,来获取到被点击的Graphic列表,转至这个Raycast中。

30eaf5ee2a62a79ded5c579efb32ea92.png

在这个Raycast中,调用了该Raycaster所属Canvas中的所有符合条件的GraphicRaycast方法,根据返回值决定是否将其最终放入results列表中。

接下来转至GraphicRaycast方法中。

ce929f78f08562a190dfcd8736048ac3.png

724f6d2a8ef396369a7a8b0e7b47734d.png

首先会获取该Graphic所在物体的所有组件,然后遍历这些组件,根据组件类型进行处理。其中比较重要的是对ICanvasRaycastFilterIsRaycastLocationValid的调用,会根据这个调用的返回值来决定该Graphic是否被点击了。ICanvasRaycastFilter接口有多个实现类,笔者此处以最常见的Image为例,转至Image所实现的IsRaycastLocationValid中。

08e5784e6a659ff252430b665b00913d.png

其中进行了大量的坐标计算,并以最终计算结果来判断是否被点击到,其中并无任何涉及物理射线的地方。

到这里,便可以回答本文开头所提出的问题了:UGUI中的点击判断,是通过坐标计算得出的,而非是之前广泛流传的射线检测。

至于为何之前存在如此广泛的误解,笔者猜想大概是被Raycast这个极具迷惑性的API命名所误导,而又未深入阅读源码所导致的。

另外,本文之前所探究的都是GraphicRaycaster下的点击判断原理,那么PhysicsRaycasterPhysics2DRaycaster下的点击判断又是如何检测的呢?与GraphicRaycaster的复杂调用不同,只需看下此二者者的Raycast实现便可知晓。

PhysicsRaycaster:

9e7e9513ad5a0a4ca14adf29ded5add1.png

Physics2DRaycaster:

19702a4c7e4e7b04358b4bb09448cb3e.png

可以看出,二者在实现上是极为相似的,与GrahicRaycaster通过计算坐标判断UI点击不同,PhysicsRaycasterPhysics2DRaycaster都是通过物理射线来进行2D/3D物体的点击判断。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值