Unity3D使用GL实现图案解锁功能

聊天是时候看到有人问如何在Unity3D的UGUI中实现图案解锁的功能,然后便试了一下。刚开始想用LineRender来实现,但又一想是要在UGUI中,然后就用了另外一种方法,即使用GL类来实现。

GL相关介绍及官方文档

实现后在Android手机上跑的效果如下:

主要实现GraphicUnLockManager类。代码如下:

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,如下设置:

接下来就可以在编辑器中运行看看结果了!按下鼠标左键开始选择,释放结束选择,效果如下:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Unity3D使用GL实现图案解锁功能

    聊天是时候看到有人问如何在Unity3D的UGUI中实现图案解锁的功能,然后便试了一下.刚开始想用LineRender来实现,但又一想是要在UGUI中,然后就用了另外一种方法,即使用GL类来实现. GL相关介绍及官方文档 实现后在Android手机上跑的效果如下: 主要实现GraphicUnLockManager类.代码如下: using UnityEngine; using System.Collections.Generic; using System; using UnityEngine.

  • Android仿手机QQ图案解锁功能

    本文实例为大家分享了Android仿手机QQ图案解锁的具体代码,供大家参考,具体内容如下 ps:请不要再问我,为什么导入之后会乱码了. 其实,代码基本上都是从原生系统中提取的:LockPatternView.加密工具类,以及解锁逻辑等,我只是稍作修改,大家都知道,原生系统界面比较丑陋,因此,我特意把QQ的apk解压了,从中拿了几张图案解锁的图片,一个简单的例子就这样诞生了. 好了,废话不多说,我们来看看效果(最后两张是最新4.4系统,炫一下,呵呵): 1.最关健的就是那个自定义九宫格View,代

  • 轻松实现Android自定义九宫格图案解锁

    Android实现九宫格图案解锁,自带将图案转化成数字密码的功能,代码如下: LockPatternView.java package com.jackie.lockpattern; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.text.TextUtils; i

  • Android 仿小米锁屏实现九宫格解锁功能(无需图片资源)

    最近公司要求做个九宫格解锁,本人用的是小米手机,看着他那个设置锁屏九宫格很好看,就做了该组件,不使用图片资源,纯代码实现. 尊重每个辛苦的博主,在http://blog.csdn.net/mu399/article/details/38734449的基础上进行修改 效果图: 关键代码类: MathUtil.Java /** * @author SoBan * @create 2016/12/5 15:52. */ public class MathUtil { public static dou

  • Android中判断屏幕是否亮屏和是否解锁功能

    1.屏幕是否亮屏: PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); //true为打开,false为关闭 boolean ifOpen = powerManager.isScreenOn(); 2.屏幕是否解锁: KeyguardManager mKeyguardManager = (KeyguardManager) context.getSystemServi

  • Android 5秒学会使用手势解锁功能

    Android手势解锁 本文讲述的是一个手势解锁的库,可以定制显示隐藏宫格点.路径.并且带有小九宫格显示图,和震动!让你学会使用这个简单,高效的库! 先来一波效果效果展示: 手势解锁效果 今天给大家介绍的是本人良心制作的一个手势解锁开源库,大家有什么建议和想法都可以发到我的邮箱: diosamolee2014@gmail.com 或者评论,我会为大家提供我力所能及的帮助! GitHub地址: https://github.com/Diosamo/Gesture_Lock 添加依赖: 添加的gra

  • Python+uiautomator2实现手机锁屏解锁功能

    业务需求:需要测试手机滑动解锁失败时事件的次数及等待的时间,本来想利用Python+Appium实现,但是Appium运行时自动给我解锁了.... 部分解释摘抄自:https://testerhome.com/topics/11357 python-uiautomator2是一个自动化测试开源工具,仅支持Android平台的原生应用测试 python-uiautomator2封装了谷歌自带的uiautomator2测试框架,提供便利的python接口.他允许测试人员直接在PC上编写Python的

  • 基于Flutter实现手势密码加密与解锁功能

    目录 前言 1.绘制静态图形 2.存储手势密码数据 3.添加手势交互 4.绘制.刷新密码线 5.加入密码错误动画 总结 前言 密码的由来:在公元前405年,由古希腊和斯巴达的战争中,由于斯巴达盟友波斯帝国背叛,导致古希腊和斯巴达两败俱伤,这时斯巴达抓了一个波斯国的信使,这个信使 没有任何情报,只有一条有着杂乱无章的希腊字母的普通腰带,最终斯巴达统帅破解了这条腰带,成功击败了希腊.这就是世界上最早的密码.同时也是世界上最早的解密. 密码在我们生活中无处不在,作为个人隐私的最后一道防线显得无比的重要

  • Android实现九宫格图案解锁

    本文实例为大家分享了Android实现九宫格图案解锁的具体代码,供大家参考,具体内容如下 前言:自定义了一个九宫格的VIew来绘制九宫格图案,实现了绘制图案解锁的功能. 效果图如下: 1. 第一步 自定义九宫格View. public class LockPatterView extends View {     private static final int POINT_SIZE = 5;     private Point[][] points = new Point[3][3];    

  • 浅析IOS开发TouchID指纹解锁功能

    效果图如下 实现过程 1.首先引入指纹解锁必须的头文件 #import <LocalAuthentication/LocalAuthentication.h> 2.了解下主要的两个方法 这个方法是判断设备是否支持TouchID的. - (BOOL)canEvaluatePolicy:(LAPolicy)policy error:(NSError * __autoreleasing *)error __attribute__((swift_error(none))); 这个是用来验证TouchI

随机推荐