Unity UGUI不规则区域按钮点击实现
Posted 剑起苍穹
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity UGUI不规则区域按钮点击实现相关的知识,希望对你有一定的参考价值。
如下图 想要实现精确的点击不发生遮挡的情况
UGUI 想要只点击表盘有反应的效果 (点击箭头处没有反应)
原理:精灵像素检测
UGUI在处理控件是否被点击的时候,主要是根据IsRaycastLocationValid这个方法的返回值来进行判断的,而这个方法用到的基本原理则是判断指定点对应像素的RGBA数值中的Alpha是否大于某个指定临界值。
例如,我们知道半透明通常是指Alpha=0.5,而对一个后缀名为png格式的图片来说半透明或者完全透明的区域理论上不应该被响应的,所以根据这个原理,我们只需要设定一个透明度的临界值,然后对当前鼠标位置对应的像素进行判断就可以了
重要的一点
下面是重写 IsRaycastLocationValid 的方法 直接挂在按钮上即可
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /// <summary> /// 不规则按钮点击 核心代码 /// </summary> [RequireComponent(typeof(Image))] public class BuGuiZhe : MonoBehaviour, ICanvasRaycastFilter { private Image image_; private Sprite sprite_; [Tooltip("设定Sprite响应的Alpha阈值")] //工具功能提示 [Range(0, 0.5f)] public float alpahThreshold = 0.5f; void Start() { image_ = GetComponent<Image>(); } /// 重写IsRaycastLocationValid接口 public bool IsRaycastLocationValid(Vector2 vtor2, Camera main_Camera) { sprite_ = image_.sprite; var rectTransform = (RectTransform)transform; Vector2 localPositionPivotRelative; RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)transform, vtor2, main_Camera, out localPositionPivotRelative); // 转换为以屏幕左下角为原点的坐标系 var localPosition = new Vector2(localPositionPivotRelative.x + rectTransform.pivot.x * rectTransform.rect.width, localPositionPivotRelative.y + rectTransform.pivot.y * rectTransform.rect.height); var spriteRect = sprite_.textureRect; var maskRect = rectTransform.rect; var x = 0; var y = 0; // 转换为纹理空间坐标 switch (image_.type) { case Image.Type.Sliced: { var border = sprite_.border; // x 轴裁剪 if (localPosition.x < border.x) { x = Mathf.FloorToInt(spriteRect.x + localPosition.x); } else if (localPosition.x > maskRect.width - border.z) { x = Mathf.FloorToInt(spriteRect.x + spriteRect.width - (maskRect.width - localPosition.x)); } else { x = Mathf.FloorToInt(spriteRect.x + border.x + ((localPosition.x - border.x) / (maskRect.width - border.x - border.z)) * (spriteRect.width - border.x - border.z)); } // y 轴裁剪 if (localPosition.y < border.y) { y = Mathf.FloorToInt(spriteRect.y + localPosition.y); } else if (localPosition.y > maskRect.height - border.w) { y = Mathf.FloorToInt(spriteRect.y + spriteRect.height - (maskRect.height - localPosition.y)); } else { y = Mathf.FloorToInt(spriteRect.y + border.y + ((localPosition.y - border.y) / (maskRect.height - border.y - border.w)) * (spriteRect.height - border.y - border.w)); } } break; case Image.Type.Simple: default: { // 转换为统一UV空间 x = Mathf.FloorToInt(spriteRect.x + spriteRect.width * localPosition.x / maskRect.width); y = Mathf.FloorToInt(spriteRect.y + spriteRect.height * localPosition.y / maskRect.height); } break; } try { return sprite_.texture.GetPixel(x, y).a > alpahThreshold; } catch (UnityException e) { Debug.LogError("请检查图片设置是不是已经勾选: Advanced/Read/Write Enabled\'" + e.Message); // 如果texture导入过程报错,则删除组件 //Destroy(this); return false; } } }
然后在按钮上绑定方法进行测试 (测试脚本如下)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class Btn_coner : MonoBehaviour { private Button btn; int sdsd = 0; // Start is called before the first frame update void Start() { btn = this.GetComponent<Button>(); btn.onClick.AddListener(delegate { sdsd++; Debug.Log(string.Format("点击了{0}次", sdsd)); }); } }
如果感觉还是不太准确,可能还有那么一点点偏移(偏下)
在设置一下就好,一般来说不设置的话也感觉不出来的(反正我是没有感觉出来,哈哈哈)
记录一下方便以后使用.
以上是关于Unity UGUI不规则区域按钮点击实现的主要内容,如果未能解决你的问题,请参考以下文章