欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-07-22 20:35:53
聊天是时候看到有人问如何在unity3d的ugui中实现图案解锁的功能,然后便试了一下。刚开始想用linerender来实现,但又一想是要在ugui中,然后就用了另外一种方...

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

gl相关介绍及官方文档

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

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

主要实现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才会被正确调用,使线能够在场景中的物体都渲染完成后再绘制。

创建连接点,如下设置:

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

设置graphicunlockmanager,如下设置:

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

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

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

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