HollowOutMask.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. /// <summary>
  4. /// 实现镂空效果的Mask组件
  5. /// </summary>
  6. public class HollowOutMask : MaskableGraphic, ICanvasRaycastFilter
  7. {
  8. [SerializeField]
  9. private RectTransform _target;
  10. private Vector3 _targetMin = Vector3.zero;
  11. private Vector3 _targetMax = Vector3.zero;
  12. private bool _canRefresh = true;
  13. private Transform _cacheTrans = null;
  14. [SerializeField]
  15. public bool isTargetRectCanThrough = true;
  16. /// <summary>
  17. /// 设置镂空的目标
  18. /// </summary>
  19. public void SetTarget(RectTransform target)
  20. {
  21. _canRefresh = true;
  22. _target = target;
  23. _RefreshView();
  24. }
  25. public RectTransform GetTarget()
  26. {
  27. return _target;
  28. }
  29. private void _SetTarget(Vector3 tarMin, Vector3 tarMax)
  30. {
  31. if (tarMin == _targetMin && tarMax == _targetMax) return;
  32. _targetMin = tarMin;
  33. _targetMax = tarMax;
  34. SetAllDirty();
  35. }
  36. private void _RefreshView()
  37. {
  38. if (!_canRefresh) return;
  39. _canRefresh = false;
  40. if (null == _target)
  41. {
  42. _SetTarget(Vector3.zero, Vector3.zero);
  43. SetAllDirty();
  44. }
  45. else
  46. {
  47. Bounds bounds = RectTransformUtility.CalculateRelativeRectTransformBounds(_cacheTrans, _target);
  48. _SetTarget(bounds.min, bounds.max);
  49. }
  50. }
  51. public void RefreshViewImmediate()
  52. {
  53. _canRefresh = true;
  54. _RefreshView();
  55. }
  56. protected override void OnPopulateMesh(VertexHelper vh)
  57. {
  58. if (_targetMin == Vector3.zero && _targetMax == Vector3.zero)
  59. {
  60. base.OnPopulateMesh(vh);
  61. return;
  62. }
  63. vh.Clear();
  64. // 填充顶点
  65. UIVertex vert = UIVertex.simpleVert;
  66. vert.color = color;
  67. Vector2 selfPiovt = rectTransform.pivot;
  68. Rect selfRect = rectTransform.rect;
  69. float outerLx = -selfPiovt.x * selfRect.width;
  70. float outerBy = -selfPiovt.y * selfRect.height;
  71. float outerRx = (1 - selfPiovt.x) * selfRect.width;
  72. float outerTy = (1 - selfPiovt.y) * selfRect.height;
  73. // 0 - Outer:LT
  74. vert.position = new Vector3(outerLx, outerTy);
  75. vh.AddVert(vert);
  76. // 1 - Outer:RT
  77. vert.position = new Vector3(outerRx, outerTy);
  78. vh.AddVert(vert);
  79. // 2 - Outer:RB
  80. vert.position = new Vector3(outerRx, outerBy);
  81. vh.AddVert(vert);
  82. // 3 - Outer:LB
  83. vert.position = new Vector3(outerLx, outerBy);
  84. vh.AddVert(vert);
  85. // 4 - Inner:LT
  86. vert.position = new Vector3(_targetMin.x, _targetMax.y);
  87. vh.AddVert(vert);
  88. // 5 - Inner:RT
  89. vert.position = new Vector3(_targetMax.x, _targetMax.y);
  90. vh.AddVert(vert);
  91. // 6 - Inner:RB
  92. vert.position = new Vector3(_targetMax.x, _targetMin.y);
  93. vh.AddVert(vert);
  94. // 7 - Inner:LB
  95. vert.position = new Vector3(_targetMin.x, _targetMin.y);
  96. vh.AddVert(vert);
  97. // 设定三角形
  98. vh.AddTriangle(4, 0, 1);
  99. vh.AddTriangle(4, 1, 5);
  100. vh.AddTriangle(5, 1, 2);
  101. vh.AddTriangle(5, 2, 6);
  102. vh.AddTriangle(6, 2, 3);
  103. vh.AddTriangle(6, 3, 7);
  104. vh.AddTriangle(7, 3, 0);
  105. vh.AddTriangle(7, 0, 4);
  106. }
  107. bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 screenPos, Camera eventCamera)
  108. {
  109. if (!isTargetRectCanThrough) return true;
  110. if (null == _target) return true;
  111. // 将目标对象范围内的事件镂空(使其穿过)
  112. return !RectTransformUtility.RectangleContainsScreenPoint(_target, screenPos, eventCamera);
  113. }
  114. protected override void Awake()
  115. {
  116. base.Awake();
  117. _cacheTrans = GetComponent<RectTransform>();
  118. }
  119. [SerializeField] public bool autoUpdate = false;
  120. private float _lastAutoUpdateTime = 0;
  121. void Update()
  122. {
  123. if (autoUpdate && Time.realtimeSinceStartup - _lastAutoUpdateTime > 0.2f) {
  124. _lastAutoUpdateTime = Time.realtimeSinceStartup;
  125. RefreshViewImmediate();
  126. }
  127. }
  128. }