前言

UGUI中的按钮默认是矩形的,若要实现非矩形按钮该怎么做呢?比如这样的按钮:

本文将介绍两种实现方式供大家选择。

使用alphaHitTestMinimumThreshold

Image类的alphaHitTestMinimumThreshold是一个浮点值,Raycast检测时只有图片中高于该值的部分会抛出点击事件。因此我们可以使用一张alpha通道的值高于该设置值的Sprite用于自定义按钮的点击相应区域。

我们准备一张点击区域alpha高于某值,非点击区域alpha低于某值的Sprite用于Button的Image组件的Sprite。然后给这个Button挂上如下脚本组件即可:

using UnityEngine;
using UnityEngine.UI;public class AlphaButton : MonoBehaviour
{public float alphaThreshold = 0.1f;void Start() {GetComponent<Image>().alphaHitTestMinimumThreshold = alphaThreshold;}
}

但这种方法有几个问题:

  1. 由于是代码中需要读取图片的alpha值用于比较,因此图片在导入时需要开启Readable/Write Enable,这样会使运行时贴图大小翻倍,内存中会额外存储一份贴图数据,增大内存开销。
  2. 如果是点击区域内部需要有一些低于设置值的透明样式则无法满足。
  3. 点击区域的调整需要修改图片资源,十分不便。

如果可以接受这些缺点,可以使用这个方法。

使用IsRaycastLocationValid

通过继承Image并重写IsRaycastLocationValid方法可以自定义按钮的可点击区域。

将如下代码放置于项目中:

using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR using UnityEditor;#endif
[RequireComponent(typeof(PolygonCollider2D))]
public class NonRectangularButtonImage : Image
{private PolygonCollider2D areaPolygon;protected NonRectangularButtonImage() {useLegacyMeshGeneration = true;}private PolygonCollider2D Polygon{get{if (areaPolygon != null)return areaPolygon;areaPolygon = GetComponent<PolygonCollider2D>();return areaPolygon;}}protected override void OnPopulateMesh(VertexHelper vh) {vh.Clear();}public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera) {return Polygon.OverlapPoint(eventCamera.ScreenToWorldPoint(screenPoint));}#if UNITY_EDITOR protected override void Reset() {base.Reset();transform.localPosition = Vector3.zero;var w = rectTransform.sizeDelta.x * 0.5f + 0.1f;var h = rectTransform.sizeDelta.y * 0.5f + 0.1f;Polygon.points = new[]{new Vector2(-w, -h),new Vector2(w, -h),new Vector2(w, h),new Vector2(-w, h)};}
#endif
}
#if UNITY_EDITOR
[CustomEditor(typeof(NonRectangularButtonImage), true)]
public class CustomRaycastFilterInspector : Editor
{public override void OnInspectorGUI() {}
}public class NonRectAngularButtonImageHelper
{[MenuItem("GameObject/UI/NonRectangularButtonImage")]public static void CreateNonRectAngularButtonImage() {var goRoot = Selection.activeGameObject;if (goRoot == null)return;var button = goRoot.GetComponent<Button>();if (button == null){Debug.Log("Selecting Object is not a button!");return;}// 关闭原来button的射线检测var graphics = goRoot.GetComponentsInChildren<Graphic>();foreach (var graphic in graphics){graphic.raycastTarget = false;}var polygon = new GameObject("NonRectangularButtonImage");polygon.AddComponent<PolygonCollider2D>();polygon.AddComponent<NonRectangularButtonImage>();polygon.transform.SetParent(goRoot.transform, false);polygon.transform.SetAsLastSibling();}
}#endif

这段代码大部分参考自雨松大神的这篇文章:

UGUI研究院之不规则按钮的响应区域(十四)

还额外写了一个自动添加组件和设置raycastTarget属性的菜单项。创建完一个普通的按钮后,右键执行命令:

这将自动创建一个名为“NonRectangularButtonImage”的子节点,并添加一个同名的脚本组件和一个PolygonCollider2D组件。编辑PolygonCollider2D组件即可设置按钮的点击区域,调整起来也十分方便,既简单又节省内存。

我的Github中这两种方式都有实现,供大家参考:

共三组按钮,点击后可以在Console窗口中看到响应Log。

第一组是没有任何处理的普通按钮,由于在Hierarchy中RightButton在下,点击Left的右下角还是右边按钮响应,用于对照。

第二组使用了设置alphaHitTestMinimumThreshold的方式。

第三组使用了重写IsRaycastLocationValid的方式,并故意调整了Button在Hierarchy中的顺序。

如果可以,也希望大家点个Star。

专栏文章继续更新,欢迎关注微信公众号:Unity与图形学

参考

使用alphaHitTestMinimumThreshold的方式

UGUI研究院之不规则按钮的响应区域(十四)

使用mask的方式

Image.alphaHitTestMinimumThreshold

ICanvasRaycastFilter.IsRaycastLocationValid

ugui unity 取消选择_UGUI中几种不规则按钮的实现方式相关推荐

  1. ugui unity 取消选择_关于Unity中的UGUI优化,你可能遇到这些问题

    ​关键字 界面制作 ​网格重建 ​界面切换 ​加载相关 ​字体 ​ 一.界面制作 Q1:UGUI里的这个选项 ,应该是ETC2拆分Alpha通道的意思,但是在使用中并没起作用?请问有没有什么拆分的标准 ...

  2. ugui unity 取消选择_Unity暑期萌新入门:环境篇

    大家好,新一期又跟大家见面了. 上一节我们完成了角色的移动控制,然而John只能在空白的场景中移动.因此接下来这一节我们将添加关卡.调节光照,让John来到阴森的鬼屋.然后设置NavMesh(导航网格 ...

  3. Unity(游戏)中五种数据存储的方法

    Unity(游戏)中五种数据存储的方法 一.PlayerPrefs unity3d提供了一个用于本地持久化保存与读取的类-------PlayerPrefs.工作原理很简单,以键值对的形式将数据保存在 ...

  4. JavaScript中四种不同的属性检测方式比较

    JavaScript中四种不同的属性检测方式比较 1. 用in方法 var o = {x:1}; "x" in o; //true "y" in o; //fa ...

  5. Extjs中三种不同的数据提交方式

    Extjs中三种不同的数据提交方式 Extjs的三种提交方式: 表单Ajax提交,普通提交,单独Ajax提交: 1.表单ajax提交(默认提交方式) 提交函数:当按下表单中的提交按钮时执行下面的btn ...

  6. H.266/VVC相关技术学习笔记21:帧间预测中五种Merge模式的熵编码方式

    今天主要详细讲一下帧间预测中五种Merge模式的熵编码方式,以及对应的VTM的代码中的编码方式的实现.现阶段VTM6.0中Merge模式大致上分为五种,分别是Subblock_Merge.MMVD_M ...

  7. java 输出文件到mac路径_Java 中几种获取文件路径的方式

    原标题:Java 中几种获取文件路径的方式 1. 前言 Java开发中我们经常要获取文件的路径,比如读取配置文件等等.今天我们就关于文件的路径和如何读取文件简单地探讨一下. 2. 文件的路径 文件的路 ...

  8. 电气工程中一种较好的电缆编号方式

    电气工程中一种较好的电缆编号方式 电气二次专业电缆号均由6位字符组成,前两位可为数字或字母,分别代表电缆两端连接设备所代表的系统,遵从由小到大,先数字后字母的原则:后四位为数字,每组数字区域段代表了电 ...

  9. R中6种读入表格数据的方式哪个最快?结果出人意料!

    R怎么读入表格数据最快? R中有6个常用数据读取函数: utils::read.csv: 默认使用的读入方式 (read.table) readr::read_csv: readr包中的读入函数 (R ...

最新文章

  1. java -jar debug_java – 如何在运行时调试jar?
  2. java按字节截取字符串牛客网_字符串计数
  3. jfinal 源码中文乱码解决
  4. Excel如何快速插入行,删除行
  5. 汉字编码与拼音输入法
  6. Gitlab Code Review
  7. 简单高效的图片降噪方法
  8. 我国重点区域加快智慧城市规划布局
  9. 【您的凭据不工作】win7远程桌面提示,请输入新凭据。登录没有成功
  10. 项目:机器学习+FLD分类+python图像处理mnist数据集
  11. 个人常用VScode插件及其配置
  12. 什么是反向代理服务器
  13. Spring源码深度解析(郝佳)-学习-Spring Boot体系原理
  14. IOS 图标尺寸以及设备尺寸详解
  15. 用python绘制heatmap
  16. php iframe做浮窗,巧用iframe做浮层
  17. 基于PIC16F876A的摇摇棒
  18. 由学生就业难想到ERP的经典语录
  19. 广播视频android,咪咪云广播视频Android版
  20. 定义一个结构体变量(包括年月日),计算该日在本年中是第几天?

热门文章

  1. 用分布式缓存提升ASP.NET Core性能
  2. OpenID Connect:OAuth 2.0协议之上的简单身份层
  3. 使用ElasticSearch,Kibana,ASP.NET Core和Docker可视化数据
  4. Vue如何在data中正确引入图片路径
  5. python中字典长度可变吗_Python:如何给字典分配一个长度可变的列表值?
  6. 【QGIS入门实战精品教程】4.1:QGIS栅格数据地理配准完整操作流程
  7. 【错误异常大全】:ArcGIS version not specified. You must call RuntimeManager.Bind before creating any ArcGIS
  8. 【MATLAB统计分析与应用100】案例001:matlab使用Importdata函数导入文本txt数据
  9. 多种语言《九九乘法表》荟萃:C、C++、C#、JavaScript、SQL、VB、VBA、Python
  10. Android之百度地图定位最详细使用总结