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

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

       });

   }

}

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

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

相关文章
|
2月前
|
前端开发 图形学 开发者
【独家揭秘】那些让你的游戏瞬间鲜活起来的Unity UI动画技巧:从零开始打造动态按钮,提升玩家交互体验的绝招大公开!
【9月更文挑战第1天】在游戏开发领域,Unity 是最受欢迎的游戏引擎之一,其强大的跨平台发布能力和丰富的功能集让开发者能够迅速打造出高质量的游戏。优秀的 UI 设计对于游戏至关重要,尤其是在手游市场,出色的 UI 能给玩家留下深刻的第一印象。Unity 的 UGUI 系统提供了一整套解决方案,包括 Canvas、Image 和 Button 等组件,支持添加各种动画效果。
117 3
|
3月前
|
图形学
小功能⭐️Unity Button按钮实现鼠标移入移出触发相应事件
小功能⭐️Unity Button按钮实现鼠标移入移出触发相应事件
|
5月前
|
图形学
【unity小技巧】实现FPS武器的瞄准放大效果(UGUI实现反向遮罩,全屏遮挡,局部镂空效果)
【unity小技巧】实现FPS武器的瞄准放大效果(UGUI实现反向遮罩,全屏遮挡,局部镂空效果)
69 1
|
5月前
|
数据可视化 大数据 API
【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用
【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用
163 0
|
5月前
|
编解码 前端开发 Java
【推荐100个unity插件之12】UGUI的粒子效果(UI粒子)—— Particle Effect For UGUI (UI Particle)
【推荐100个unity插件之12】UGUI的粒子效果(UI粒子)—— Particle Effect For UGUI (UI Particle)
311 0
|
5月前
|
开发工具 图形学
【推荐100个unity插件之11】Shader实现UGUI的特效——UIEffect为 Unity UI 提供视觉效果组件
【推荐100个unity插件之11】Shader实现UGUI的特效——UIEffect为 Unity UI 提供视觉效果组件
270 0
|
5月前
|
前端开发 图形学
技术经验解读:【Unity3d游戏开发】UGUI插件入门之游戏菜单
技术经验解读:【Unity3d游戏开发】UGUI插件入门之游戏菜单
28 0
|
6月前
|
前端开发 C# 图形学
unity按钮绑定与场景切换
unity按钮绑定与场景切换
53 0
|
6月前
|
编解码 前端开发 人机交互
【Unity 3D】UI系统中UGUI各个组件的详细讲解(附源码 超详细)
【Unity 3D】UI系统中UGUI各个组件的详细讲解(附源码 超详细)
259 0
|
3月前
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
144 6