| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- using UnityEngine;
- using UnityEngine.UI;
- /// <summary>
- /// 实现镂空效果的Mask组件
- /// </summary>
- public class HollowOutMask : MaskableGraphic, ICanvasRaycastFilter
- {
- [SerializeField]
- private RectTransform _target;
-
- private Vector3 _targetMin = Vector3.zero;
- private Vector3 _targetMax = Vector3.zero;
-
- private bool _canRefresh = true;
- private Transform _cacheTrans = null;
- [SerializeField]
- public bool isTargetRectCanThrough = true;
-
- /// <summary>
- /// 设置镂空的目标
- /// </summary>
- public void SetTarget(RectTransform target)
- {
- _canRefresh = true;
- _target = target;
- _RefreshView();
- }
- public RectTransform GetTarget()
- {
- return _target;
- }
-
- 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
- {
- Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(_cacheTrans, _target);
- _SetTarget(bounds.min, bounds.max);
- }
- }
- public void RefreshViewImmediate()
- {
- _canRefresh = true;
- _RefreshView();
- }
-
- 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: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(_targetMin.x, _targetMax.y);
- vh.AddVert(vert);
- // 5 - Inner:RT
- vert.position = new Vector3(_targetMax.x, _targetMax.y);
- vh.AddVert(vert);
- // 6 - Inner:RB
- vert.position = new Vector3(_targetMax.x, _targetMin.y);
- vh.AddVert(vert);
- // 7 - Inner:LB
- vert.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 (!isTargetRectCanThrough) return true;
- if (null == _target) return true;
- // 将目标对象范围内的事件镂空(使其穿过)
- return !RectTransformUtility.RectangleContainsScreenPoint(_target, screenPos, eventCamera);
- }
-
- protected override void Awake()
- {
- base.Awake();
- _cacheTrans = GetComponent<RectTransform>();
- }
- [SerializeField] public bool autoUpdate = false;
- private float _lastAutoUpdateTime = 0;
- void Update()
- {
- if (autoUpdate && Time.realtimeSinceStartup - _lastAutoUpdateTime > 0.2f) {
- _lastAutoUpdateTime = Time.realtimeSinceStartup;
- RefreshViewImmediate();
- }
- }
- }
|