Unity3D使用GL实现图案解锁功能
程序员文章站
2023-11-25 18:17:52
聊天是时候看到有人问如何在unity3d的ugui中实现图案解锁的功能,然后便试了一下。刚开始想用linerender来实现,但又一想是要在ugui中,然后就用了另外一种方...
聊天是时候看到有人问如何在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,如下设置:
接下来就可以在编辑器中运行看看结果了!按下鼠标左键开始选择,释放结束选择,效果如下:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。