Unity实现多平台二维码扫描
程序员文章站
2023-09-03 16:45:10
在unity里做扫二维码的功能,虽然有插件,但是移动端ui一般不能自定义,所以后来自已做了一个,直接在c#层扫描解析,ui上就可以自己发挥了。
上代码:
这个是调用zx...
在unity里做扫二维码的功能,虽然有插件,但是移动端ui一般不能自定义,所以后来自已做了一个,直接在c#层扫描解析,ui上就可以自己发挥了。
上代码:
这个是调用zxing的脚本。
using unityengine; using system.collections; using zxing; using zxing.qrcode; public class qr { /// <summary> /// 解析二维码 /// </summary> /// <param name="tex"></param> /// <returns></returns> public static string decode(texture2d tex) { return decodecoldata(tex.getpixels32(), tex.width, tex.height); //通过reader解码 } public static string decodecoldata(color32[] data, int w, int h) { barcodereader reader = new barcodereader(); result result = reader.decode(data, w, h); //通过reader解码 //gc.collect(); if (result == null) return ""; else { return result.text; } } /// <summary> /// 生成二维码 /// </summary> /// <param name="content"></param> /// <param name="len"></param> /// <returns></returns> public static texture2d getqrtexture(string content, int len = 256) { var bw = new barcodewriter(); bw.format = barcodeformat.qr_code; bw.options = new zxing.common.encodingoptions() { height = len, width = len }; var cols = bw.write(content); texture2d t = new texture2d(len, len); t.setpixels32(cols); t.apply(); return t; } }
然后是封装:
using unityengine; using system.collections; using system; using unityengine.ui; using system.timers; /// <summary> /// 二维码解析工具 /// 关键函数: /// public static qrhelper getinst() --得到单例 /// public event action<string> onqrscanned; --扫描回调 /// public void startcamera(int index) --启动摄像头 /// public void stopcamera() --停止摄像头 /// public void settoui(rawimage raw,int uilayoutw,int uilayouth) --把摄像机画面设置到一个rawimage上并使它全屏显示 /// </summary> public class qrhelper { public event action<string> onqrscanned; private static qrhelper _inst; public static qrhelper getinst() { if (_inst == null) { _inst = new qrhelper(); } return _inst; } private int reqw = 640; private int reqh = 480; private webcamtexture webcam; timer timer_in, timer_out; /// <summary> /// 启动摄像头 /// </summary> /// <param name="index">手机后置为0,前置为1</param> public void startcamera(int index) { stopcamera(); lock (mutex) { buffer = null; tbuffer = null; } var dev = webcamtexture.devices; webcam = new webcamtexture(dev[index].name); webcam.requestedwidth = reqw; webcam.requestedheight = reqh; webcam.play(); stopanalysis = false; inittimer(); timer_in.start(); timer_out.start(); } /// <summary> /// 停止 /// </summary> public void stopcamera() { if (webcam!=null) { webcam.stop(); unityengine.object.destroy(webcam); resources.unloadunusedassets(); webcam = null; stopanalysis = true; timer_in.stop(); timer_out.start(); timer_in = null; timer_out = null; } } /// <summary> /// 把摄像机画面设置到一个rawimage上并使它全屏显示 /// </summary> /// <param name="raw">rawimage</param> /// <param name="uilayoutw">ui布局时的宽度</param> /// <param name="uilayouth">ui布局时的高度</param> public void settoui(rawimage raw,int uilayoutw,int uilayouth){ raw.getcomponent<recttransform>().sizedelta = getwh(uilayoutw,uilayouth); int d = -1; if (webcam.videoverticallymirrored) { d = 1; } raw.getcomponent<recttransform>().localrotation *= quaternion.angleaxis(webcam.videorotationangle, vector3.back); float scaley = webcam.videoverticallymirrored ? -1.0f : 1.0f; raw.transform.localscale = new vector3(1, scaley * 1, 0.0f); raw.texture = webcam; raw.color = color.white; } //在考虑可能旋转的情况下计算ui的宽高 private vector2 getwh(int uilayoutw, int uilayouth) { int angle = webcam.videorotationangle; vector2 init = new vector2(reqw, reqh); if ( angle == 90 || angle == 270 ) { var tar = init.scaletocontain(new vector2(uilayouth,uilayoutw)); return tar; } else { var tar = init.scaletocontain(new vector2(uilayoutw, uilayouth)); return tar; } } private void inittimer() { timer_in = new timer(500); timer_in.autoreset = true; timer_in.elapsed += (a,b) => { threadwrapper.invoke(writedatabuffer); }; timer_out = new timer(900); timer_out.autoreset = true; timer_out.elapsed += (a,b)=>{ analysis(); }; } private color32[] buffer = null; private color32[] tbuffer = null; private object mutex = new object(); private bool stopanalysis = false; int dw, dh; private void writedatabuffer() { lock (mutex) { if (buffer == null && webcam!=null) { buffer = webcam.getpixels32(); dw = webcam.width; dh = webcam.height; } } } //解析二维码 private void analysis() { if (!stopanalysis) { lock (mutex) { tbuffer = buffer; buffer = null; } if (tbuffer == null) { ; } else { string str = qr.decodecoldata(tbuffer, dw, dh); tbuffer = null; if (!str.isnullorempty() && onqrscanned != null) { threadwrapper.invoke(() => { if (onqrscanned!=null) onqrscanned(str); }); } } } tbuffer = null; } }
调用方式如下,用了puremvc,可能理解起来有点乱,也不能直接用于你的工程,主要看onregister和onremove里是怎么启动和停止的,以及regqrcb、removeqrcb、onqrsccanned如何注册、移除以及响应扫描到二维码的事件的。在onregister中,由于ios上画面有镜象,所以把rawimage的scale的y置为了-1以消除镜像:
using unityengine; using system.collections; using system.collections.generic; using puremvc.patterns; using puremvc.interfaces; /// <summary> /// 扫描二维码界面逻辑 /// </summary> public class scanqrmediator : mediator { audioproxy audio; public qrview tarview { get { return base.viewcomponent as qrview; } } public scanqrmediator() : base("scanqrmediator") { } string nextview = ""; bool isinitover = false; int cameradelay = 1; public override void onregister() { base.onregister(); if (application.platform == runtimeplatform.iphoneplayer) { cameradelay = 5; } else { cameradelay = 15; } audio = appfacade.inst.retrieveproxy<audioproxy>("audioproxy"); tarview.btnback.onclick.addlistener(btnescclick); qrhelper.getinst().startcamera(0); tarview.webcamcontent.recttransform.localeulerangles = vector3.zero; coroutinewrapper.exef(cameradelay, () => { regqrcb(); qrhelper.getinst().settoui(tarview.webcamcontent, 1536, 2048); if (application.platform == runtimeplatform.iphoneplayer) { tarview.webcamcontent.recttransform.localscale = new vector3(1, -1, 0); } isinitover = true; }); umengstatistics.pv(tarview); //暂停背景音乐 audio.setbgactive(false); } public override void onremove() { base.onremove(); tarview.btnback.onclick.removelistener(btnescclick); if (nextview != "unlockview") { audio.setbgactive(true); } nextview = ""; isinitover = false; } bool isesc = false; void btnescclick() { if (isesc || !isinitover) { return; } isesc = true; tarview.webcamcontent.texture = null; tarview.webcamcontent.color = color.black; removeqrcb(); qrhelper.getinst().stopcamera(); coroutinewrapper.exef(cameradelay, () => { isesc = false; if (application.platform == runtimeplatform.iphoneplayer) { touserinfoview(); } else { string origin = tarview.lastarg.sget<string>("origin"); if (origin == "arview") { toarview(); } else if (origin == "userinfoview") { touserinfoview(); } else { toarview(); } } }); } void toarview() { appfacade.inst.removemediator(this.mediatorname); viewmgr.getinst().showview(tarview, "arview", null); } void touserinfoview() { appfacade.inst.removemediator(this.mediatorname); viewmgr.getinst().showview(tarview, "userinfoview", null); var v = viewmgr.getinst().peektop(); var vc = new userinfomediator(); vc.viewcomponent = v; appfacade.inst.registermediator(vc); } int reg = 0; void regqrcb() { if (reg == 0) { qrhelper.getinst().onqrscanned += onqrscanned; reg = 1; } } void removeqrcb() { if (reg == 1) { qrhelper.getinst().onqrscanned -= onqrscanned; reg = 0; } } bool isqrjump = false; void onqrscanned(string qrstr) { if (isqrjump) { return; } isqrjump = true; tarview.webcamcontent.texture = null; tarview.webcamcontent.color = color.black; removeqrcb(); qrhelper.getinst().stopcamera(); nextview = "unlockview"; coroutinewrapper.exef(cameradelay, () => { isqrjump = false; appfacade.inst.removemediator(this.mediatorname); audio.playscanedeffect(); #if yx_debug debug.log("qr is :"+qrstr); toast.showtext(qrstr,1.5f); #endif viewmgr.getinst().showview(tarview, "unlockview", hashtableex.construct("qrcode", qrstr, "origin", tarview.lastarg.sget<string>("origin"))); var v = viewmgr.getinst().peektop(); var vc = new unlockmediator(); vc.viewcomponent = v; appfacade.inst.registermediator(vc); }); } }
最后,放上zxing.unity.dll,放在plugins里就可以了。
以上代码5.1.2测试可用。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。