分享

【100个 Unity实用技能】☀️ | Unity中 过滤透明区域的点击事件

 敲代码的小Y 2024-01-22 发布于上海

请添加图片描述


Unity 实用技能学习

Unity中 过滤透明区域的点击事件

在Unity中我们有时候会遇到一些带有透明度的图片按钮,有些时候可能并不希望点击按钮的透明区域时也触发点击事件,这个时候就要进行额外处理,下面整理了几种方法可以进行参考使用!

在这里插入图片描述

像素检测 过滤透明区域

这种方法是通过读取Sprite在某一点的像素值(RGBA),如果该点的像素值中的Alpha小于一定的阈值(比如0.5)则表示该点是透明的,即用户点击的位置在精灵边界以外,否则用户点击的位置在精灵边界内部。

这种做法就是通过判断点击的某一点是否达到我们期望的像素Alpha阈值,达到阈值就响应事件,未达到阈值就说明点击了透明区域,此时不响应事件。

UGUI在处理控件是否被点击的时候,主要是根据IsRaycastLocationValid这个方法的返回值来进行判断的,而这个方法用到的基本原理则是判断指定点对应像素的RGBA数值中的Alpha是否大于某个指定临界值。

一、使用Image组件自带的参数检测

而UGUI中可以通过Image组件拿到一个alphaHitTestMinimumThreshold ,这个值代表的含义就是期望的像素Alpha阈值,通过改变这个值就可以实现过滤透明区域的点击事件。

this.GetComponent<Image>().alphaHitTestMinimumThreshold = 0.1f;

所以使用方法很简单,拿到指定按钮上的Image组件,改变这个Image的alphaHitTestMinimumThreshold即可实现过滤透明区域的所有点击事件,下面看下实际使用方法及效果。

通过控制alpahThreshold的值可以实现透明过滤的强度,也就是透明度过滤的预制。比如alpahThreshold 为0则代表只过滤全透明的区域,alpahThreshold 为0.5则是把半透明一下的过滤掉,alpahThreshold 为1的话那就整张图都被过滤了,都不会响应事件。

准备两个带有透明度的切图,然后放置到场景的Button组件上,测试代码如下:

using UnityEngine;using UnityEngine.UI;public class UnityImageAlphaTest : MonoBehaviour{public Button btnImage1;public Button btnImage2;[Header("透明度过滤阈值")]public float alpahThreshold = 0.5f;void Start(){btnImage1.onClick.AddListener(OnClickImage);btnImage2.onClick.AddListener(OnClickImage);btnImage2.GetComponent<Image>().alphaHitTestMinimumThreshold = alpahThreshold;}private void OnClickImage(){Debug.Log("点击图片测试!");}}

值得注意的是还需要把过滤透明区域的图片设置为可读写状态(Read/Write Enable 设置为true),如下图所示,否则这种方法不会生效且会报错。
在这里插入图片描述

将两个Button挂载到脚本中,第一个Button不参与透明过滤,第二个Button过滤透明区域点击事件。
在这里插入图片描述

此时运行Unity就可以看到效果了,效果如下:
请添加图片描述

2.根据点击的坐标计算该点的像素值是否满足阈值

与上述直接使用Image组件的方法有所区别,这种方法是通过计算我们点击的坐标点的像素值是否达到阈值来判断需要过滤。

但原理是相同的,都是通过像素检测去判断是否选择过滤,下面看下实现代码:

using UnityEngine;using UnityEngine.UI;public class Model_ButtonSetting : MonoBehaviour, ICanvasRaycastFilter{[Header("透明度过滤阈值")]public float alpahThreshold = 0.1f;protected Image _image;void Start(){_image = GetComponent<Image>();}public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera){//将选中的点转换为Image区域内的本地点Vector2 localPoint;RectTransformUtility.ScreenPointToLocalPointInRectangle(_image.rectTransform, sp, eventCamera, out localPoint);Vector2 pivot = _image.rectTransform.pivot;Vector2 normalizedLocal = new Vector2(pivot.x + localPoint.x / _image.rectTransform.rect.width, pivot.y + localPoint.y / _image.rectTransform.rect.height);Vector2 uv = new Vector2(_image.sprite.rect.x + normalizedLocal.x * _image.sprite.rect.width,_image.sprite.rect.y + normalizedLocal.y * _image.sprite.rect.height);uv.x /= _image.sprite.texture.width;uv.y /= _image.sprite.texture.height;//获取指定纹理坐标(u, v)处的像素颜色。它返回一个Color结构,其中包含红、绿、蓝和alpha通道的值。//Color c = _image.sprite.texture.GetPixel((int)uv.x, (int)uv.y);//用于在纹理上执行双线性插值以获取像素颜色值,这个方法使用双线性插值算法来估算纹理中某个位置的颜色,而不是直接从纹理的像素中读取颜色。Color c = _image.sprite.texture.GetPixelBilinear(uv.x, uv.y);return c.a > alpahThreshold;}}

这种方法也需要把过滤透明区域的图片设置为可读写状态(Read/Write Enable 设置为true),否则这种方法也不会生效且会报错。

将上述脚本挂载到需要屏蔽透明区域的按钮上即可生效,简单易用。


    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多