本文实例为大家分享了Unity实现新手引导镂空效果的具体代码,供大家参考,具体内容如下
一、实现思路
创建有8个顶点的Mesh,内外边界都是四边形(矩形)。只生成内、外边之间的Mesh,内层矩形就产生了镂空部分,外层的4个顶点,是组件自身RectTransform的四个顶点,内层的4个顶点,使用镂空目标(_target)RectTransform的四个顶点。确定内层的顶点的时候需要注意,多数情况下_target和HollowOutMask都不在同一个本地坐标空间,所以需要使用CalculateRelativeRectTransformBounds计算出HollowOutMask空间下坐标
这种镂空的表现,可以稍稍提高下性能。因为镂空的位置不参与渲染,Overdraw会降低
UGUI提供了ICanvasRaycastFilter接口,我们实现IsRaycastLocationValid方法,就可以很方便的控制HollowOutMask是否要拦截下在某一点触发的事件
二、这个组件的作用
这个组件做了两件事情:表现上镂空一块区域和不拦截镂空范围上的事件
三、代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
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 ; /// <summary> /// 设置镂空的目标 /// </summary> public void SetTarget(RectTransform target) { _canRefresh = true ; _target = target; _RefreshView(); } 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); } } 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 ( null == _target) return true ; // 将目标对象范围内的事件镂空(使其穿过) return !RectTransformUtility.RectangleContainsScreenPoint(_target, screenPos, eventCamera); } protected override void Awake() { base .Awake(); _cacheTrans = GetComponent<RectTransform>(); } #if UNITY_EDITOR void Update() { _canRefresh = true ; _RefreshView(); } #endif } |
四、使用说明
将以上组件挂载到有RectTransform组件的游戏物体身上,设置Color的颜色以及Target区域的大小即可
——此组件挂载的游戏物体身上只能有一个继承Graphics类的组件
——若自定义添加Image控制Target区域大小,记得将Image的Alpha设置为0并且取消射线检测
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/LLLLL__/article/details/104263122