浅谈Unity之UGUI不规则区域按钮点击实现

本文涉及的产品
交互式建模 PAI-DSW,5000CU*H 3个月
简介: UGUI不规则区域按钮点击实现

前言:每日记录自己学习unity的心得和体会,小弟才疏学浅,如有错误的地方,欢迎大佬们指正,感谢~


如下图   想要实现精确的点击不发生遮挡的情况


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));

       });

   }

}

如果感觉还是不太准确,可能还有那么一点点偏移(偏下)

在设置一下就好,一般来说不设置的话也感觉不出来的(反正我是没有感觉出来,哈哈哈)

相关文章
|
4月前
|
编解码 前端开发 人机交互
【Unity 3D】UI系统中UGUI各个组件的详细讲解(附源码 超详细)
【Unity 3D】UI系统中UGUI各个组件的详细讲解(附源码 超详细)
81 0
|
8月前
|
图形学
Unity UGUI如何计算drawcall
Unity UGUI如何计算drawcall
|
图形学
Unity中UGUI、粒子系统、Mesh混合使用保证层级正确
把粒子、Mesh渲染到一张RenderTexture上,然后把这张RenderTexture贴到一张RawImage就可以解决这种类似的UI,Mesh,粒子穿插使用的问题。这种方法由于比较麻烦就没有使用。
|
vr&ar 图形学
【Unity3D 灵巧小知识点】☀️ | Unity通过 射线 获取 鼠标的世界坐标 和 鼠标点击的物体信息
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。
【Unity3D 灵巧小知识点】☀️ | Unity通过 射线 获取 鼠标的世界坐标 和 鼠标点击的物体信息
|
vr&ar 图形学
【Unity3D 灵巧小知识点】☀️ | Unity UGUI组件Scroll View禁止 左右 或 上下 滑动
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。 也可以简单把 Unity 理解为一个游戏引擎,可以用来专业制作游戏!
【Unity3D 灵巧小知识点】☀️ | Unity UGUI组件Scroll View禁止 左右 或 上下 滑动
|
API 图形学 Android开发
创作 【Unity使用UGUI实现王者荣耀UI界面(四)】游戏开始界面
创作 【Unity使用UGUI实现王者荣耀UI界面(四)】游戏开始界面
393 0
创作 【Unity使用UGUI实现王者荣耀UI界面(四)】游戏开始界面
|
API 图形学 Python
【Unity使用UGUI实现王者荣耀UI界面(三)】登录界面以及加载界面优化
【Unity使用UGUI实现王者荣耀UI界面(三)】登录界面以及加载界面优化
240 0
【Unity使用UGUI实现王者荣耀UI界面(三)】登录界面以及加载界面优化
|
前端开发 图形学 Python
【Unity使用UGUI实现王者荣耀UI界面(二)】加载页面-静音按钮和页面完善
【Unity使用UGUI实现王者荣耀UI界面(二)】加载页面-静音按钮和页面完善
330 0
【Unity使用UGUI实现王者荣耀UI界面(二)】加载页面-静音按钮和页面完善
|
4月前
|
C# 图形学
【Unity 3D】元宇宙案例之虚拟地球信息射线实战(附源码、演示视频和步骤 超详细)
【Unity 3D】元宇宙案例之虚拟地球信息射线实战(附源码、演示视频和步骤 超详细)
50 0
|
4月前
|
人工智能 自然语言处理 区块链
【Unity 3D】元宇宙概念、应用前景、价值链等概述
【Unity 3D】元宇宙概念、应用前景、价值链等概述
52 0