聊天是时候看到有人问如何在Unity3D的UGUI中实现图案解锁的功能,然后便试了一下。刚开始想用LineRender来实现,但又一想是要在UGUI中,然后就用了另外一种方法,即使用GL类来实现。
GL相关介绍及官方文档
实现后在Android手机上跑的效果如下:
主要实现GraphicUnLockManager类。代码如下:
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
|
using UnityEngine; using System.Collections.Generic; using System; using UnityEngine.EventSystems; using UnityEngine.UI; public class GraphicUnLockManager : MonoBehaviour { [Tooltip( "含有Selectable及Image组件的UI对象,作为连接点。" )] public List<RectTransform> _lstPoints = new List<RectTransform>(); [Tooltip( "用于设置所画线的颜色。(可使用“unlit/Color”Shader)" )] public Material _matLineColor; [Tooltip( "用于设置所画线的高度。" )] public int _nHalfHeight = 15; [Tooltip( "用于设置选择时Image的颜色。" )] public Color _clrSelect = Color.red; [Tooltip( "用于设置未选择时Image的颜色。" )] public Color _clrUnSelect = Color.white; [HideInInspector] public List<RectTransform> _lstSelectPoints = new List<RectTransform>(); //已选择连接点 [HideInInspector] public List< int > _lstPassword = new List< int >(); //以输入密码 [HideInInspector] public Action< bool > onInputState; //true为开始输入,false为结束输入 private bool _isPressing = false ; //是否按下 private Vector2 _vtPressPos; //按下点坐标 private float _fDistance; //距离 private float _fDegree; //夹角 private Matrix4x4 _matrixTrans; //变换矩阵 private Vector2[] _vertexPos = new Vector2[4]; //顶点数组 private Vector2 _tempPos; void Awake() { InitEnterEvent(); //初始化所有连接点的消息 ClearLines(); //清空相关数据 } void Update() { if (!IsPressed()) { //当未按下时清空是数据 ClearLines(); } } bool IsPressed() { //触摸 if (Input.touchCount > 0) { switch (Input.touches[0].phase) { case TouchPhase.Began: _isPressing = true ; if (onInputState != null ) { onInputState( true ); //状态改变 } break ; case TouchPhase.Ended: case TouchPhase.Canceled: _isPressing = false ; if (onInputState != null ) { onInputState( false ); //状态改变 } break ; } _vtPressPos = Input.touches[0].position; } else { //鼠标 if (Input.GetMouseButtonDown(0)) { _isPressing = true ; if (onInputState != null ) { onInputState( true ); //状态改变 } } if (Input.GetMouseButtonUp(0)) { _isPressing = false ; if (onInputState != null ) { onInputState( false ); //状态改变 } } _vtPressPos = Input.mousePosition; } return _isPressing; } void OnPostRender() { DrawLines(); //画所有线 } void OnGUI() { string msg = "" ; msg += "是否正在输入:" + IsPressed() + "\n" ; msg += "密码:" ; for ( int i = 0; i < _lstPassword.Count; i++) { msg += _lstPassword[i] + "," ; } GUIStyle guiStyle = new GUIStyle(); guiStyle.normal.textColor = new Color(1, 1, 1); //设置字体颜色 guiStyle.fontSize = 75; //设置字体大小 GUILayout.Label(msg, guiStyle); } void InitEnterEvent() { //为每个点添加Enter事件 _lstPoints.ForEach((rtTrans) => { EventTrigger trigger = rtTrans.GetComponent<EventTrigger>(); if (trigger == null ) { trigger = rtTrans.gameObject.AddComponent<EventTrigger>(); } //添加事件 EventTrigger.Entry entryEnter = new EventTrigger.Entry(); entryEnter.eventID = EventTriggerType.PointerEnter; //进入事件 EventTrigger.TriggerEvent evtEnter = new EventTrigger.TriggerEvent(); evtEnter.AddListener(OnSelectPoint); entryEnter.callback = evtEnter; trigger.triggers.Add(entryEnter); EventTrigger.Entry entryDown= new EventTrigger.Entry(); entryDown.eventID = EventTriggerType.PointerDown; //按下事件 EventTrigger.TriggerEvent evtDown = new EventTrigger.TriggerEvent(); evtDown.AddListener(OnSelectPoint); entryDown.callback = evtDown; trigger.triggers.Add(entryDown); }); } public void OnSelectPoint(BaseEventData obj) { //转换数据类型 PointerEventData data = obj as PointerEventData; GameObject target = null ; if ( null != data.pointerEnter) { target = data.pointerEnter; } else if ( null != data.pointerPress) { target = data.pointerPress; } AddSelectPoint(target); //添加选择连接点 } void AddSelectPoint(GameObject obj) { if (IsPressed() && null != obj) { //将未连接的点添加到需要连接的点的列表中去 RectTransform rtTrans = obj.GetComponent<RectTransform>(); if ( null != rtTrans && !_lstSelectPoints.Contains(rtTrans)) { //添加到绘制列表 _lstSelectPoints.Add(rtTrans); //添加密码序列 _lstPassword.Add(_lstPoints.IndexOf(rtTrans)); //改变颜色 rtTrans.GetComponent<Image>().color = _clrSelect; } } } void ClearLines() { //清空选择及密码列表 _lstSelectPoints.Clear(); _lstPassword.Clear(); //还原颜色 _lstPoints.ForEach((rtTrans) => { rtTrans.GetComponent<Image>().color = _clrUnSelect; }); } void DrawLine(Vector2 vtStart, Vector2 vtEnd) { _tempPos = vtEnd - vtStart; _fDistance = Vector3.Distance(Vector3.zero, _tempPos); //距离 _fDegree = Vector3.Angle(_tempPos, Vector3.right); //与x轴正方向的夹角 //判断旋转方向,逆时针为正,顺时针为付 if (_tempPos.y < 0) { _fDegree *= -1; } //设置变换矩阵 _matrixTrans.SetTRS(vtStart, Quaternion.Euler(0, 0, _fDegree), Vector3.one); //设置变换矩阵 //设置绘制顶点坐标 _vertexPos[0].x = 0; _vertexPos[0].y = -_nHalfHeight; _vertexPos[1].x = 0; _vertexPos[1].y = _nHalfHeight; _vertexPos[2].x = _fDistance; _vertexPos[2].y = _nHalfHeight; _vertexPos[3].x = _fDistance; _vertexPos[3].y = -_nHalfHeight; //绘制 GL.PushMatrix(); GL.LoadPixelMatrix(); //使(0,0,0)为左下角,(Screen.width,Screen.height,0)为右上角 GL.MultMatrix(_matrixTrans); GL.Begin(GL.QUADS); //绘制四边形 for ( int n = 0; n < 4; n++) { GL.Vertex(_vertexPos[n]); } GL.End(); GL.PopMatrix(); } void DrawLines() { //设置线的材质 _matLineColor.SetPass(0); //连接已选择的点 for ( int nIndex = 0; nIndex < _lstSelectPoints.Count - 1; nIndex++) { DrawLine(_lstSelectPoints[nIndex].position, _lstSelectPoints[nIndex + 1].position); } //连接到Press点 if (IsPressed() && _lstSelectPoints.Count > 0) { DrawLine(_vtPressPos, _lstSelectPoints[_lstSelectPoints.Count - 1].position); } } } |
上面的实现中都有注明,如有不清楚的地方请留言。绘制主要在DrawLine函数中。
然后将GraphicUnLockManager类添加到MainCamera上,只有这样OnPostRender才会被正确调用,使线能够在场景中的物体都渲染完成后再绘制。
创建连接点,如下设置:
设置GraphicUnLockManager,如下设置:
接下来就可以在编辑器中运行看看结果了!按下鼠标左键开始选择,释放结束选择,效果如下:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/u012741077/article/details/52551181