Unity UI 镂空遮罩组件教程 - 实现教程镂空效果
Unity UI 镂空遮罩组件教程 - 实现教程镂空效果
本文介绍如何在Unity中使用MaskableGraphic组件实现镂空遮罩效果,并解决常见问题,例如场景中多个EventSystem导致的冲突。
代码示例:
using Skillx.Utils;
using UnityEngine;
using UnityEngine.UI;
namespace NoviceTutorial
{
/// <summary>
/// 实现镂空效果的Mask组件
/// </summary>
public class TutorialHollowOutMask : MaskableGraphic, ICanvasRaycastFilter
{
[SerializeField] private RectTransform highLightTarget;
private Vector3 mTargetMin = Vector3.zero;
private Vector3 mTargetMax = Vector3.zero;
private bool mCanRefresh = true;
private Transform mCacheTrans = null;
/// <summary>
/// 设置高亮区域的位置大小
/// </summary>
/// <param name="target"></param>
public void SetTarget(RectTransform target)
{
if (highLightTarget == null)
{
return;
}
highLightTarget.position = target.position;
highLightTarget.sizeDelta = target.sizeDelta;
mCanRefresh = true;
RefreshView();
}
private void SetTarget(Vector3 tarMin, Vector3 tarMax)
{
if (tarMin == mTargetMin && tarMax == mTargetMax)
return;
mTargetMin = tarMin;
mTargetMax = tarMax;
SetAllDirty();
}
private void RefreshView()
{
if (!mCanRefresh)
{
return;
}
mCanRefresh = false;
if (null == highLightTarget)
{
SetTarget(Vector3.zero, Vector3.zero);
}
else
{
Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(mCacheTrans, highLightTarget);
SetTarget(bounds.min, bounds.max);
}
}
protected override void OnPopulateMesh(VertexHelper vh)
{
if (mTargetMin == Vector3.zero && mTargetMax == 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:LT
vert.position = new Vector3(outerLx, outerTy);
vh.AddVert(vert);
// 1 - Outer:RT
vert.position = new Vector3(outerRx, outerTy);
vh.AddVert(vert);
// 2 - Outer:RB
vert.position = new Vector3(outerRx, outerBy);
vh.AddVert(vert);
// 3 - Outer:LB
vert.position = new Vector3(outerLx, outerBy);
vh.AddVert(vert);
// 4 - Inner:LT
vert.position = new Vector3(mTargetMin.x, mTargetMax.y);
vh.AddVert(vert);
// 5 - Inner:RT
vert.position = new Vector3(mTargetMax.x, mTargetMax.y);
vh.AddVert(vert);
// 6 - Inner:RB
vert.position = new Vector3(mTargetMax.x, mTargetMin.y);
vh.AddVert(vert);
// 7 - Inner:LB
vert.position = new Vector3(mTargetMin.x, mTargetMin.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 (highLightTarget == null)
{
return true;
}
// 将目标对象范围内的事件镂空(使事件可以穿透)
var isClickHighLightArea = RectTransformUtility.RectangleContainsScreenPoint(highLightTarget, screenPos, eventCamera);
//点击到高亮区域时,射线可以穿透
if (!isClickHighLightArea)
{
//判断下方是否有引导窗口,如果有的话,通知引导进行下一步
var uiTutorialRoot = GoHelper.FindGameObject(transform.parent.gameObject, "TutorialUIRoot");
var uiTutorial = uiTutorialRoot.GetComponentInChildren<UITutorial>();
if (uiTutorial != null)
{
uiTutorial.Next();
}
}
return !isClickHighLightArea;
}
protected override void Awake()
{
base.Awake();
mCacheTrans = GetComponent<RectTransform>();
}
void Update()
{
mCanRefresh = true;
RefreshView();
}
}
}
解决场景中多个EventSystem导致的冲突:
挂上该组件后,如果场景中存在多个EventSystem,可能会出现以下报错:
(来自t Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/GraphicRaycaster.cs:332)
这是因为每个场景只能有一个EventSystem来处理用户输入事件。
解决方法:
- 打开场景中的Hierarchy面板。
- 查找并删除多余的EventSystem对象。可以通过点击对象并按下Delete键来删除。
- 确保只剩下一个EventSystem对象。
如果你不确定哪个对象是EventSystem,可以在Inspector面板中查看对象的组件列表,找到包含EventSystem组件的对象。
完成以上步骤后,重新运行场景,报错应该就不再出现了。
使用说明:
- 将TutorialHollowOutMask组件添加到需要进行镂空效果的UI元素上。
- 在Inspector面板中设置highLightTarget属性,该属性对应需要被镂空遮罩的区域。
注意:
- 该组件可以与其他UI元素(例如Button、Image等)一起使用,实现更加丰富的交互效果。
- 如果需要实现动态镂空效果,可以在代码中动态调整highLightTarget属性的值。
应用场景:
- 常见的教程引导效果,可以将高亮区域设置为当前需要用户操作的UI元素。
- 自定义形状的UI遮罩效果,例如圆形、三角形等。
- 游戏中需要实现特定区域事件穿透的场景。
总结:
通过使用MaskableGraphic组件,可以轻松地在Unity UI中实现镂空遮罩效果。在使用过程中,需要注意场景中EventSystem的数量,并根据具体需求进行调整。
原文地址: https://www.cveoy.top/t/topic/qeTr 著作权归作者所有。请勿转载和采集!