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

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测试可用。

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