ITPub博客

首页 > IT职业 > IT生活 > 【Unity游戏开发】UGUI不规则区域点击的实现

【Unity游戏开发】UGUI不规则区域点击的实现

IT生活 作者:cnaka 时间:2021-09-09 09:39:00 0 删除 编辑

一、简介

  马三从上一家公司离职了,最近一直在出去面试,忙得很,所以这一篇博客拖到现在才写出来。马三在上家公司工作的时候,曾处理了一个UGUI不规则区域点击的问题,制作过程中也有一些收获和需要注意坑,因此记录成博客与大家分享。众所周知在UGUI中,响应点击通常是依附在一张图片上的,而图片不管美术怎么给你切,导进Unity之后都是一个矩形,如果要做其他形状,最多只能旋转一下,或者自己做一些处理。而为了美术效果,很多时候我们不得不需要特定形状的UI,并且让它们实现精准的响应点击。例如下图就是一个不规则的点击区域。

图片描述

      图1:UGUI不规则点击区域示意图

  下面是处理了不规则区域点击后的演示效果,当点击按钮的时候,会对点击次数进行累加并且打印到控制台。可以看到进行了不规则区域点击处理以后,对我们原来的普通矩形Sprite的点击不会产生到影响,而不规则区域的表现效果也符合我们的预期。

图片描述

图2:规则区域与不规则区域点击效果对比

回到顶部PayneQin大神已经在他的博客中做了很详细的解析和说明,大家可以直接去看他的博客。知乎上关于判断一个点是否在多边形内部也有很多算法地讨论,具体可以看这里。其中这篇文献提供了判断一个点是否在任意多边形内部的两种方法,分别为Corssing Number和Winding Number。这两种方法在理论层面的相关细节请大家自行阅读这篇文章,PayneQin大神选择的是前者实现,其基本思想是计算从该点引出的射线与多边形边界相交的次数,当其为奇数时表示该点在多边形内部,当其为偶数时表示在多边形外部。马三在网上找到了相关的实现(偷懒):

图片描述

 1 bool ContainsPoint2(Vector2[] polyPoints,Vector2 p) 2 { 3     //统计射线和多边形交叉次数 4     int cn = 0; 5  6     //遍历多边形顶点数组中的每条边 7     for(int i=0; i ().position.x;11         polyPoints [i].y += transform.GetComponent ().position.y;12 13         //从当前位置发射向上向下两条射线14         if(((polyPoints [i].y  p.y)) 
15             || ((polyPoints [i].y > p.y) && (polyPoints [i + 1].y 

图片描述

  基于上面算法制作的多边形碰撞器实现的不规则按钮,以正五边形举例(PayneQin大神实现,马三只是搬运工):

图片描述

 1 /* 2  * 基于多边形碰撞器实现的不规则按钮 
 3  * 作者:PayneQin 4  * 日期:2016年7月9日 5  */ 6  7 using UnityEngine; 8 using System.Collections; 9 using UnityEngine.UI;10 using UnityEngine.EventSystems;11 12 public class UnregularButtonWithCollider : MonoBehaviour,IPointerClickHandler13 {14     /// 15     /// 多边形碰撞器16     /// 17     PolygonCollider2D polygonCollider;18 19     void Start()20     {21         //获取多边形碰撞器22         polygonCollider = transform.GetComponent();23     }24 25 26     public void OnPointerClick(PointerEventData eventData)27     {28         //对2D屏幕坐标系进行转换29         Vector2 local;30         local.x = eventData.position.x - (float)Screen.width / 2.0f;31         local.y = eventData.position.y - (float)Screen.height / 2.0f;32         if(ContainsPoint(polygonCollider.points,local))33         {34 35             Debug.Log ("这是一个正五边形!");36         }37 38     }39 40     /// 41     /// 判断指定点是否在给定的任意多边形内42     /// 43     bool ContainsPoint(Vector2[] polyPoints,Vector2 p)44     {45         //统计射线和多边形交叉次数46         int cn = 0;47 48         //遍历多边形顶点数组中的每条边49         for(int i=0; i ().position.x;53             polyPoints [i].y += transform.GetComponent ().position.y;54 55             //从当前位置发射向上向下两条射线56             if(((polyPoints [i].y  p.y)) 
57                || ((polyPoints [i].y > p.y) && (polyPoints [i + 1].y 

图片描述

回到顶部这篇文章,才找到问题的症结所在。

  对于如下图所示的这种周围有空白区域的图片,我们需要在Unity图片导入设置的时候,将Mesh Type格式设置为Full Rect,而unity导入时默认帮我们设置的是Tight模式。

图片描述         图片描述

图5:周围有空白的图片                                                                                     图6:正确的导入设置

   那么,它们有什么区别呢?关于它们的区别,Unity官方是这样解释的:

图片描述

图7:Full Rect和Tight两种Mesh Type的官方解释

  总的来说就是,用Tight模式的话,如果你的图片周围有空白像素,它会帮你压缩掉减小面积,以减少DrawCall,但是会增加Sprite的面数。如果用Full Rect模式不会压缩,也不会增加面数,直接创建一个quab,然后把图片扔上去。如果尺寸小于32x32的话,Unity默认使用Full Rect格式导入,否则使用Tight格式导入。因此如果我们不对Mesh Type进行设置的话,原来的一些空白区域就相当于裁剪掉了,这样相对于左下角的坐标来说,一些像素坐标就发生了偏移,而我们使用的是像素检测方法,必然也会导致偏移误差。

回到顶部

四、总结

  通过本篇博客,马三和大家一起学习了如何在Unity中实现UGUI不规则区域的点击,希望本篇博客能为大家的工作过程中带来一些帮助与启发。

参考资料:

  • https://blog.csdn.net/qinyuanpei/article/details/51868638

  • https://blog.csdn.net/shenmifangke/article/details/53504036

  • https://www.zhihu.com/question/26551754?f3fb8ead20=b6b9d1289bcc893ff2fa0abd1e65fc52

原文出处:https://www.cnblogs.com/msxh/p/9283266.html

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/3368/viewspace-2805579/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-08-14

  • 博文量
    79
  • 访问量
    754