Unity3D使用GL實(shí)現(xiàn)圖案解鎖功能
聊天是時(shí)候看到有人問(wèn)如何在Unity3D的UGUI中實(shí)現(xiàn)圖案解鎖的功能,然后便試了一下。剛開(kāi)始想用LineRender來(lái)實(shí)現(xiàn),但又一想是要在UGUI中,然后就用了另外一種方法,即使用GL類來(lái)實(shí)現(xiàn)。
GL相關(guān)介紹及官方文檔
實(shí)現(xiàn)后在Android手機(jī)上跑的效果如下:

主要實(shí)現(xiàn)GraphicUnLockManager類。代碼如下:
using UnityEngine;
using System.Collections.Generic;
using System;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class GraphicUnLockManager : MonoBehaviour
{
[Tooltip("含有Selectable及Image組件的UI對(duì)象,作為連接點(diǎn)。")]
public List<RectTransform> _lstPoints = new List<RectTransform>();
[Tooltip("用于設(shè)置所畫(huà)線的顏色。(可使用“unlit/Color”Shader)")]
public Material _matLineColor;
[Tooltip("用于設(shè)置所畫(huà)線的高度。")]
public int _nHalfHeight = 15;
[Tooltip("用于設(shè)置選擇時(shí)Image的顏色。")]
public Color _clrSelect = Color.red;
[Tooltip("用于設(shè)置未選擇時(shí)Image的顏色。")]
public Color _clrUnSelect = Color.white;
[HideInInspector]
public List<RectTransform> _lstSelectPoints = new List<RectTransform>();//已選擇連接點(diǎn)
[HideInInspector]
public List<int> _lstPassword = new List<int>();//以輸入密碼
[HideInInspector]
public Action<bool> onInputState;//true為開(kāi)始輸入,false為結(jié)束輸入
private bool _isPressing = false;//是否按下
private Vector2 _vtPressPos;//按下點(diǎn)坐標(biāo)
private float _fDistance;//距離
private float _fDegree;//夾角
private Matrix4x4 _matrixTrans;//變換矩陣
private Vector2[] _vertexPos = new Vector2[4];//頂點(diǎn)數(shù)組
private Vector2 _tempPos;
void Awake()
{
InitEnterEvent();//初始化所有連接點(diǎn)的消息
ClearLines();//清空相關(guān)數(shù)據(jù)
}
void Update()
{
if (!IsPressed())
{//當(dāng)未按下時(shí)清空是數(shù)據(jù)
ClearLines();
}
}
bool IsPressed()
{
//觸摸
if (Input.touchCount > 0)
{
switch (Input.touches[0].phase)
{
case TouchPhase.Began:
_isPressing = true;
if (onInputState != null)
{
onInputState(true);//狀態(tài)改變
}
break;
case TouchPhase.Ended:
case TouchPhase.Canceled:
_isPressing = false;
if (onInputState != null)
{
onInputState(false);//狀態(tài)改變
}
break;
}
_vtPressPos = Input.touches[0].position;
}
else
{
//鼠標(biāo)
if (Input.GetMouseButtonDown(0))
{
_isPressing = true;
if (onInputState != null)
{
onInputState(true);//狀態(tài)改變
}
}
if (Input.GetMouseButtonUp(0))
{
_isPressing = false;
if (onInputState != null)
{
onInputState(false);//狀態(tài)改變
}
}
_vtPressPos = Input.mousePosition;
}
return _isPressing;
}
void OnPostRender()
{
DrawLines();//畫(huà)所有線
}
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); //設(shè)置字體顏色
guiStyle.fontSize = 75; //設(shè)置字體大小
GUILayout.Label(msg, guiStyle);
}
void InitEnterEvent()
{
//為每個(gè)點(diǎn)添加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;//進(jìn)入事件
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)
{
//轉(zhuǎn)換數(shù)據(jù)類型
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);//添加選擇連接點(diǎn)
}
void AddSelectPoint(GameObject obj)
{
if (IsPressed() && null != obj)
{
//將未連接的點(diǎn)添加到需要連接的點(diǎn)的列表中去
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軸正方向的夾角
//判斷旋轉(zhuǎn)方向,逆時(shí)針為正,順時(shí)針為付
if (_tempPos.y < 0)
{
_fDegree *= -1;
}
//設(shè)置變換矩陣
_matrixTrans.SetTRS(vtStart, Quaternion.Euler(0, 0, _fDegree), Vector3.one);//設(shè)置變換矩陣
//設(shè)置繪制頂點(diǎn)坐標(biāo)
_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()
{
//設(shè)置線的材質(zhì)
_matLineColor.SetPass(0);
//連接已選擇的點(diǎn)
for (int nIndex = 0; nIndex < _lstSelectPoints.Count - 1; nIndex++)
{
DrawLine(_lstSelectPoints[nIndex].position, _lstSelectPoints[nIndex + 1].position);
}
//連接到Press點(diǎn)
if (IsPressed() && _lstSelectPoints.Count > 0)
{
DrawLine(_vtPressPos, _lstSelectPoints[_lstSelectPoints.Count - 1].position);
}
}
}
上面的實(shí)現(xiàn)中都有注明,如有不清楚的地方請(qǐng)留言。繪制主要在DrawLine函數(shù)中。
然后將GraphicUnLockManager類添加到MainCamera上,只有這樣OnPostRender才會(huì)被正確調(diào)用,使線能夠在場(chǎng)景中的物體都渲染完成后再繪制。
創(chuàng)建連接點(diǎn),如下設(shè)置:

設(shè)置GraphicUnLockManager,如下設(shè)置:

接下來(lái)就可以在編輯器中運(yùn)行看看結(jié)果了!按下鼠標(biāo)左鍵開(kāi)始選擇,釋放結(jié)束選擇,效果如下:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
深入C#中使用SqlDbType.Xml類型參數(shù)的使用詳解
本篇文章是對(duì)在C#中使用SqlDbType.Xml類型參數(shù)的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
unity實(shí)現(xiàn)場(chǎng)景切換進(jìn)度條顯示
這篇文章主要為大家詳細(xì)介紹了unity實(shí)現(xiàn)場(chǎng)景切換進(jìn)度條顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
如何應(yīng)用C#實(shí)現(xiàn)UDP的分包組包
本篇文章小編將為大家介紹,如何應(yīng)用C#實(shí)現(xiàn)UDP的分包組包。需要的朋友參考下2013-04-04
C#連接SQL?Sever數(shù)據(jù)庫(kù)與數(shù)據(jù)查詢實(shí)例之?dāng)?shù)據(jù)倉(cāng)庫(kù)詳解
最近的工作遇到了連接查詢,特在此記錄,以免日后以往,下面這篇文章主要給大家介紹了關(guān)于C#連接SQL?Sever數(shù)據(jù)庫(kù)與數(shù)據(jù)查詢實(shí)例之?dāng)?shù)據(jù)倉(cāng)庫(kù)的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
在C#中使用OpenCV(使用OpenCVSharp)的實(shí)現(xiàn)
這篇文章主要介紹了在C#中使用OpenCV(使用OpenCVSharp)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11

