前言

自Unity2019之后Unity将UGUI模块从内置库修改成了通过PackageManger引入的方式。Image就来源于com.unity.modules.imgui模块。其实代码大体代码跟2018是一致的,但是还是有些细微差别,Image透明度点击不命中就是2019之后才有的问题,2018版本是没有这个问题的,我都怀疑是开发人员抄代码没抄全。

首先这个点击不命中是在你使用图集的方式打包UI图片时出现,Unity使用SpriteAtlas自动打包图集。

什么时候使用透明度点击

有时候美术做的图片,希望在交互的时候避免玩家点击空白处也能响应,但是由于图片是矩形的,这个时候就要使用透明度点击,也就是设置ImagealphaHitTestMinimumThreshold值,设置这个值需要满足以下条件:

  • Sprite所在纹理(图集)压缩格式不为Crunch类型
  • Sprite所以纹理(图集)是可读的

简述透明度点击原理

每次我们点击屏幕Unity我使用射线检查判断当前点击的对象是否可以点击。当判定到了当前点击对象的时候,会去调用IsRaycastLocationValid 来对当前点击的位置进行判断是否可以点击,如果没有设置透明度点击(alphaHitTestMinimumThreshold值为0)就直接可以点击。如果设置了就将屏幕点击点换算到Sprite所在纹理坐标中,再通过这个纹理坐标(uv)去读取这个坐标像素的alpha值,如果大于设置的alphaHitTestMinimumThreshold值就表示可以点击。

Unity的Bug

我们首先来看看Unity的源码
Image透明度点击简述以及Unity2019之后存在无法点击的BUG修复-LMLPHP
我们可以看到Unity在计算uv的时候,拿的是Sprite的Rect内的x,y坐标去除的Sprite对应的图集的尺寸,得出来的结果肯定就是错的。
正确的做法应该是拿到Sprite在图集的偏移位置除以图集的尺寸。

// Convert local coordinates to texture space.
Rect spriteRect = overrideSprite.textureRect;
float x = (spriteRect.x + local.x) / overrideSprite.texture.width;
float y = (spriteRect.y + local.y) / overrideSprite.texture.height;

虽然但是,我们知道怎么改,但是改不了,这个是Unity的基础依赖库,很多其他的库都依赖这个1.0.0版本的库,我们不能直接修改也没法升级,就只能另辟蹊径了,可以重新创建一个新的类来继承Image来重写IsRaycastLocationValid方法。
我在下面放上我修改重新的类文件,就不直接贴出来了。

11-12 13:13