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

本文涉及的产品
模型训练 PAI-DLC,100CU*H 3个月
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
交互式建模 PAI-DSW,每月250计算时 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));

       });

   }

}

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

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

相关文章
|
10天前
|
前端开发 图形学
unity UGUI跟随3D物体的坐标转换
在 Unity 中实现 UGUI 元素跟随 3D 物体,关键是将 3D 物体的世界坐标转换为屏幕或画布坐标。通过 Camera.WorldToScreenPoint 方法,可将 3D 物体位置映射到屏幕上,再更新 UGUI 元素的位置。代码示例展示了如何使用该方法,使 UGUI 图像跟随 3D 模型,并提供文字显示、图像和线条的显示/隐藏功能。
|
10天前
|
图形学
Unity 获取鼠标位置下的UGUI或3D物体
本文总结了两种检测方法,分别用于UGUI和3D物体的检测。第一种方法`GetOverUIobj`专门用于检测鼠标悬停的UGUI元素,通过`GraphicRaycaster`实现。第二种方法`GetOverWordGameObject`则同时适用于UI和3D物体检测,利用`PhysicsRaycaster`进行射线检测。两者均返回悬停对象或null。
|
10天前
|
图形学
Unity UGUI拖拽移动
本文介绍了两种UI拖拽实现方式:精准拖拽和克隆拖拽。精准拖拽通过计算鼠标点击点与UI中心的偏移量,使UI跟随鼠标移动,适用于需要精确控制的场景。代码中通过`IBeginDragHandler`、`IDragHandler`和`IEndDragHandler`接口实现拖拽逻辑。克隆拖拽则在拖拽时克隆一个UI对象,使其跟随鼠标移动,适合视觉效果需求较高的场景。代码中同样使用上述接口,并在拖拽结束时销毁克隆对象。具体实现可参考提供的代码示例。
|
11天前
|
图形学
Unity UGUI实现鼠标拖动图片
在 Unity UGUI 中实现鼠标拖动图片功能,主要涉及事件检测、坐标转换和物体位置更新。根据鼠标移动量更新图片位置。代码示例展示了如何通过这些步骤实现拖动效果。
|
11天前
|
图形学
unity一个按钮实现开和关
在 Unity 中,通过一个布尔变量 `count` 来记录按钮的状态(开/关),并在点击事件中根据该变量的值执行不同操作。代码示例展示了两种方法:一种是通过计数器的奇偶性判断状态,另一种是直接取反布尔变量。每次点击后更新状态变量,从而实现按钮的开/关切换。
|
5月前
|
前端开发 图形学 开发者
【独家揭秘】那些让你的游戏瞬间鲜活起来的Unity UI动画技巧:从零开始打造动态按钮,提升玩家交互体验的绝招大公开!
【9月更文挑战第1天】在游戏开发领域,Unity 是最受欢迎的游戏引擎之一,其强大的跨平台发布能力和丰富的功能集让开发者能够迅速打造出高质量的游戏。优秀的 UI 设计对于游戏至关重要,尤其是在手游市场,出色的 UI 能给玩家留下深刻的第一印象。Unity 的 UGUI 系统提供了一整套解决方案,包括 Canvas、Image 和 Button 等组件,支持添加各种动画效果。
306 3
|
6月前
|
图形学
小功能⭐️Unity Button按钮实现鼠标移入移出触发相应事件
小功能⭐️Unity Button按钮实现鼠标移入移出触发相应事件
|
8月前
|
数据可视化 大数据 API
【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用
【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用
357 0
|
8月前
|
图形学
【unity小技巧】实现FPS武器的瞄准放大效果(UGUI实现反向遮罩,全屏遮挡,局部镂空效果)
【unity小技巧】实现FPS武器的瞄准放大效果(UGUI实现反向遮罩,全屏遮挡,局部镂空效果)
158 1
|
5月前
|
测试技术 C# 图形学
掌握Unity调试与测试的终极指南:从内置调试工具到自动化测试框架,全方位保障游戏品质不踩坑,打造流畅游戏体验的必备技能大揭秘!
【9月更文挑战第1天】在开发游戏时,Unity 引擎让创意变为现实。但软件开发中难免遇到 Bug,若不解决,将严重影响用户体验。调试与测试成为确保游戏质量的最后一道防线。本文介绍如何利用 Unity 的调试工具高效排查问题,并通过 Profiler 分析性能瓶颈。此外,Unity Test Framework 支持自动化测试,提高开发效率。结合单元测试与集成测试,确保游戏逻辑正确无误。对于在线游戏,还需进行压力测试以验证服务器稳定性。总之,调试与测试贯穿游戏开发全流程,确保最终作品既好玩又稳定。
275 4

热门文章

最新文章