{"title":"using Skillx.Utils; \nusing UnityEngine; \nusing UnityEngine.UI; \n\nnamespace NoviceTutorial \n{ \n ///

\n /// 实现镂空效果的Mask组件 \n /// \n public class TutorialHollowOutMask : MaskableGraphic, ICanvasRaycastFilter \n { \n [SerializeField] private RectTransform highLightTarget; \n\n private Vector3 mTargetMin = Vector3.zero; \n private Vector3 mTargetMax = Vector3.zero; \n\n private bool mCanRefresh = true; \n private Transform mCacheTrans = null; \n\n /// \n /// 设置高亮区域的位置大小 \n /// \n /// \n public void SetTarget(RectTransform target) \n { \n if (highLightTarget == null) \n { \n return; \n } \n\n highLightTarget.position = target.position; \n highLightTarget.sizeDelta = target.sizeDelta; \n \n mCanRefresh = true; \n RefreshView(); \n } \n\n private void SetTarget(Vector3 tarMin, Vector3 tarMax) \n { \n if (tarMin == mTargetMin && tarMax == mTargetMax) \n return; \n mTargetMin = tarMin; \n mTargetMax = tarMax; \n SetAllDirty(); \n } \n\n private void RefreshView() \n { \n if (!mCanRefresh) \n { \n return; \n } \n \n mCanRefresh = false; \n\n if (null == highLightTarget) \n { \n SetTarget(Vector3.zero, Vector3.zero); \n } \n else \n { \n Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(mCacheTrans, highLightTarget); \n SetTarget(bounds.min, bounds.max); \n } \n } \n\n protected override void OnPopulateMesh(VertexHelper vh) \n { \n if (mTargetMin == Vector3.zero && mTargetMax == Vector3.zero) \n { \n base.OnPopulateMesh(vh); \n return; \n } \n\n vh.Clear(); \n\n // 填充顶点 \n UIVertex vert = UIVertex.simpleVert; \n vert.color = color; \n\n Vector2 selfPiovt = rectTransform.pivot; \n Rect selfRect = rectTransform.rect; \n float outerLx = -selfPiovt.x * selfRect.width; \n float outerBy = -selfPiovt.y * selfRect.height; \n float outerRx = (1 - selfPiovt.x) * selfRect.width; \n float outerTy = (1 - selfPiovt.y) * selfRect.height; \n // 0 - Outer:LT \n vert.position = new Vector3(outerLx, outerTy); \n vh.AddVert(vert); \n // 1 - Outer:RT \n vert.position = new Vector3(outerRx, outerTy); \n vh.AddVert(vert); \n // 2 - Outer:RB \n vert.position = new Vector3(outerRx, outerBy); \n vh.AddVert(vert); \n // 3 - Outer:LB \n vert.position = new Vector3(outerLx, outerBy); \n vh.AddVert(vert); \n\n // 4 - Inner:LT \n vert.position = new Vector3(mTargetMin.x, mTargetMax.y); \n vh.AddVert(vert); \n // 5 - Inner:RT \n vert.position = new Vector3(mTargetMax.x, mTargetMax.y); \n vh.AddVert(vert); \n // 6 - Inner:RB \n vert.position = new Vector3(mTargetMax.x, mTargetMin.y); \n vh.AddVert(vert); \n // 7 - Inner:LB \n vert.position = new Vector3(mTargetMin.x, mTargetMin.y); \n vh.AddVert(vert); \n\n // 设定三角形 \n vh.AddTriangle(4, 0, 1); \n vh.AddTriangle(4, 1, 5); \n vh.AddTriangle(5, 1, 2); \n vh.AddTriangle(5, 2, 6); \n vh.AddTriangle(6, 2, 3); \n vh.AddTriangle(6, 3, 7); \n vh.AddTriangle(7, 3, 0); \n vh.AddTriangle(7, 0, 4); \n } \n\n bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 screenPos, Camera eventCamera) \n { \n if (highLightTarget == null) \n { \n return true; \n } \n \n // 将目标对象范围内的事件镂空(使事件可以穿透) \n var isClickHighLightArea = RectTransformUtility.RectangleContainsScreenPoint(highLightTarget, screenPos, eventCamera); \n \n //点击到高亮区域时,射线可以穿透 \n if (!isClickHighLightArea) \n { \n //判断下方是否有引导窗口,如果有的话,通知引导进行下一步 \n var uiTutorialRoot = GoHelper.FindGameObject(transform.parent.gameObject, "TutorialUIRoot"); \n var uiTutorial = uiTutorialRoot.GetComponentInChildren(); \n if (uiTutorial != null) \n { \n uiTutorial.Next(); \n } \n } \n\n return !isClickHighLightArea; \n } \n\n protected override void Awake() \n { \n base.Awake(); \n mCacheTrans = GetComponent(); \n } \n\n void Update() \n { \n mCanRefresh = true; \n RefreshView(); \n } \n } \n}挂上后, 场景里的EventSystem有报错,来自t Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/GraphicRaycaster.cs:332) \n\n解释下为啥内容:报错来自Unity的GraphicRaycaster.cs文件的332行,这是因为在使用TutorialHollowOutMask组件时,EventSystem无法正确地处理UI事件。 \n\n具体原因是TutorialHollowOutMask实现了ICanvasRaycastFilter接口,并且重写了IsRaycastLocationValid方法来判断UI事件是否在高亮区域内。在判断过程中,如果UI事件的位置在高亮区域外,会返回true,表示事件可以继续传递给下层的UI元素。但是在判断过程中,如果UI事件的位置在高亮区域内,会返回false,表示事件被拦截,不会传递给下层的UI元素。 \n\n这就导致了EventSystem无法正确地处理UI事件,因为它依赖于GraphicRaycaster来确定哪个UI元素可以接收事件。 \n\n解决这个问题的方法是修改IsRaycastLocationValid方法的逻辑,使其正确地判断UI事件是否在高亮区域内,并返回正确的结果。具体的修改逻辑可以根据具体需求来实现,例如可以使用射线检测或者碰撞检测来判断UI事件是否在高亮区域内。 \n\n另外,如果报错是由于EventSystem的GraphicRaycaster组件引起的,可以尝试将EventSystem的GraphicRaycaster组件替换为其他的Raycaster组件,例如PhysicsRaycaster或者Physics2DRaycaster,来解决报错问题。

Unity UI 镂空遮罩组件 TutorialHollowOutMask 实现教程

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

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