using Skillx.Utils; using UnityEngine; using UnityEngine.UI; namespace NoviceTutorial { ///

/// 实现镂空效果的Mask组件 /// 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; /// /// 设置高亮区域的位置大小 /// /// 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 false; } // 将目标对象范围内的事件镂空(使事件可以穿透) var isClickHighLightArea = RectTransformUtility.RectangleContainsScreenPoint(highLightTarget, screenPos, eventCamera); //点击到高亮区域时,射线可以穿透 if (!isClickHighLightArea) { //判断下方是否有引导窗口,如果有的话,通知引导进行下一步 var uiTutorialRoot = GoHelper.FindGameObject(transform.parent.gameObject, "TutorialUIRoot"); var uiTutorial = uiTutorialRoot.GetComponentInChildren(); if (uiTutorial != null) { uiTutorial.Next(); } } return !isClickHighLightArea; } protected override void Awake() { base.Awake(); mCacheTrans = GetComponent(); } void Update() { mCanRefresh = true; RefreshView(); } } }挂上后, 场景里EventSystem有报错,来自t Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/GraphicRaycaster.cs:332) 解释下为啥。举个例子解决这个问题内容:在Unity中,EventSystem用于处理UI事件的系统。报错来自GraphicRaycaster.cs文件的332行,这是因为TutorialHollowOutMask组件实现了ICanvasRaycastFilter接口,而在该接口的IsRaycastLocationValid方法中,返回了一个bool值来确定是否允许射线检测。 报错的原因是在IsRaycastLocationValid方法中,如果highLightTarget为空,会直接返回true,即允许射线检测。然而,在场景中的EventSystem组件的GraphicRaycaster组件会使用UI元素的射线检测结果来确定是否响应点击事件。由于TutorialHollowOutMask的高亮区域为空,导致射线检测结果为空,从而导致报错。 解决这个问题的方法是在IsRaycastLocationValid方法中,判断highLightTarget是否为空,如果为空,则直接返回false,不允许射线检测。这样可以避免报错,并保证正常的UI交互。 以下是修改后的代码示例: csharp bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 screenPos, Camera eventCamera) { if (highLightTarget == null) { return false; } // 将目标对象范围内的事件镂空(使事件可以穿透) 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; } 通过以上修改,当highLightTarget为空时,返回false,不允许射线检测,避免了报错。同时,当点击到高亮区域时,射线可以穿透,可以进行下一步引导操作。

Unity UI: 使用Mask组件实现镂空效果并解决EventSystem报错

原文地址: https://www.cveoy.top/t/topic/qeTt 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录