当前位置: 首页 > news >正文

Unity Mask镂空效果(常用于新手引导或高亮显示UI元素)

在游戏中经常可以看到新手引导的效果是全屏上方有一张黑色遮罩,指定区块高亮展示,并且鼠标的点击事件可以穿透黑色遮罩点击到下方的按钮。(如下图所示)

那这个效果是怎么实现的呢?下面提供两种实现方案:

1、使用四个canvas进行拼接(理解成本低,但不推荐)

这样能保证界面中可以保留一个矩形的空白区块。由于中心区块没有任何阻挡射线检测的障碍,因此也能满足点击区域内按钮的需求

只需要知道空白区域的Rect数据,就可以计算出4个Canvas的尺寸以及位置。

优点:理解成本低,实现方法简单

缺点:Canvas之间的拼接可能会出现缝隙(与UI界面渲染逻辑有关,不太好避免)

2、重写MaskableGraphic,实现挖空效果(推荐)

主要分两步实现:
①美术效果层面的镂空展示
②射线检测层面的过滤

美术效果层面的镂空展示

OnPopulateMesh 算是一个比较经典的函数,这个可以让我们实现图片的裁剪

例如我们需要裁切中间区域:

1、先绘制一个覆盖整个屏幕的矩形(外部矩形)

2、在目标区域(内部矩形)挖空,形成镂空效果

3、顶点和三角形设置:创建8个顶点(4个外部顶点,4个内部顶点),然后通过8个三角形连接这些顶点,形成外部矩形和内部镂空区域之间的边框。

通过这种方法,实现“空白区域”的镂空效果

射线检测层面的过滤

实现`ICanvasRaycastFilter`接口的`IsRaycastLocationValid`方法

在目标区域内的点击事件可以穿透(返回false)

遮罩部分会拦截事件(返回true)

这样,只有遮罩部分响应事件,目标区域则允许事件穿透到后面的UI元素。

代码实现

using System.Collections;
using UnityEngine;
using UnityEngine.UI;namespace GameComponent
{public class GuideMask : MaskableGraphic, ICanvasRaycastFilter{[SerializeField]private RectTransform _target;private Vector3 _targetMin = Vector3.zero;private Vector3 _targetMax = Vector3.zero;private bool _canRefresh = true;private Transform _cacheTrans = null;/// <summary>/// 设置镂空的目标/// </summary>public void SetTarget(RectTransform target){_canRefresh = true;_target = target;_RefreshView();}private void _SetTarget(Vector3 tarMin, Vector3 tarMax){if (tarMin == _targetMin && tarMax == _targetMax)return;_targetMin = tarMin;_targetMax = tarMax;SetAllDirty();}private void _RefreshView(){if (!_canRefresh) return;_canRefresh = false;if (null == _target){_SetTarget(Vector3.zero, Vector3.zero);SetAllDirty();}else{StartCoroutine(RefreshNextFrame());}}private IEnumerator RefreshNextFrame(){yield return null;Vector3 targetLocalPos = _cacheTrans.InverseTransformPoint(_target.position);Rect targetRect = _target.rect;Vector2 pivot = _target.pivot;float leftOffset = targetRect.width * pivot.x;float rightOffset = targetRect.width * (1 - pivot.x);float bottomOffset = targetRect.height * pivot.y;float topOffset = targetRect.height * (1 - pivot.y);Vector3 targetMin = new Vector3(targetLocalPos.x - leftOffset, targetLocalPos.y - bottomOffset, 0);Vector3 targetMax = new Vector3(targetLocalPos.x + rightOffset, targetLocalPos.y + topOffset, 0);_SetTarget(targetMin, targetMax);}protected override void OnPopulateMesh(VertexHelper vh){if (_targetMin == Vector3.zero && _targetMax == Vector3.zero){base.OnPopulateMesh(vh);return;}vh.Clear();UIVertex vert = UIVertex.simpleVert;vert.color = color;Vector2 selfPiovt = rectTransform.pivot;Rect selfRect = rectTransform.rect;float outerLx = -selfPiovt.x * selfRect.width;float outerBy = -selfPiovt.y * selfRect.height;float outerRx = (1 - selfPiovt.x) * selfRect.width;float outerTy = (1 - selfPiovt.y) * selfRect.height;// 0 - Outer:LTvert.position = new Vector3(outerLx, outerTy);vh.AddVert(vert);// 1 - Outer:RTvert.position = new Vector3(outerRx, outerTy);vh.AddVert(vert);// 2 - Outer:RBvert.position = new Vector3(outerRx, outerBy);vh.AddVert(vert);// 3 - Outer:LBvert.position = new Vector3(outerLx, outerBy);vh.AddVert(vert);// 4 - Inner:LTvert.position = new Vector3(_targetMin.x, _targetMax.y);vh.AddVert(vert);// 5 - Inner:RTvert.position = new Vector3(_targetMax.x, _targetMax.y);vh.AddVert(vert);// 6 - Inner:RBvert.position = new Vector3(_targetMax.x, _targetMin.y);vh.AddVert(vert);// 7 - Inner:LBvert.position = new Vector3(_targetMin.x, _targetMin.y);vh.AddVert(vert);// 设定三角形vh.AddTriangle(4, 0, 1);vh.AddTriangle(4, 1, 5);vh.AddTriangle(5, 1, 2);vh.AddTriangle(5, 2, 6);vh.AddTriangle(6, 2, 3);vh.AddTriangle(6, 3, 7);vh.AddTriangle(7, 3, 0);vh.AddTriangle(7, 0, 4);}bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 screenPos, Camera eventCamera){if (null == _target) return true;// 将目标对象范围内的事件镂空(使其穿过)return !RectTransformUtility.RectangleContainsScreenPoint(_target, screenPos, eventCamera);}protected override void Awake(){base.Awake();_cacheTrans = GetComponent<RectTransform>();}#if UNITY_EDITORvoid Update(){// _canRefresh = true;// _RefreshView();}
#endif}
}

使用方法

使用GuideMask.SetTarget()赋值需要镂空的RectTransform即可

http://www.dtcms.com/a/467266.html

相关文章:

  • 网站名是什么免费视频网站大全
  • Unity实现圆柱螺旋曲线运动方程
  • wordpress企业建长沙关键词优化新报价
  • 学习爬虫第五天:自动化爬虫
  • 专业的网站建设制作服务wordpress注册字段
  • 有关网站备案号规则怎么设计网站规划方案
  • 兰州网站建设推荐q479185700顶你做阀门网站电话
  • 怎么制作微信购物网站怎么开发手机app
  • 广州翼讯资讯科技有限公司 网站wordpress更换主题白屏
  • php网站开发模式有哪些网页设计与网站建设的概述
  • 网站风格细节dede增加手机网站
  • 中国数据安全保护法介绍与实践案例
  • 龙虎榜——20251010
  • 东莞建域名网站服装网站建设定制
  • 数据结构------二叉查找树
  • 电子商务网站商品怎么来制作ppt用什么软件
  • 网站官网认证加v怎么做江苏网络推广排名
  • 《jEasyUI 创建页脚摘要》
  • 设计网站的管理系统宁波网络营销推广咨询报价
  • 优秀的移动端网站合肥快速建站在线咨询
  • 网站建设要哪些seo济南手机网站建设公司报价
  • 企业网站不足云主机免费申请
  • 合肥市庐阳区住房和城乡建设局网站深圳品牌设计公司深圳品牌设计公司
  • kali BEEF的xss注入简单应用(DVWA)
  • 按键实现短按、长按、双击、长按抬起
  • 韩国男女直接做视频网站效果图工作室
  • 嵌入式企业面经实战合集(持续更新)
  • package.xml文件的作用
  • 萍乡网站建设哪家好哦小项目加盟
  • 爱妮微如何做网站链接的网址一起做网站下载数据包