服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - Unity实现多平台二维码扫描

Unity实现多平台二维码扫描

2022-07-29 10:25阿循 C#

这篇文章主要为大家详细介绍了Unity实现多平台二维码扫描,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

在unity里做扫二维码的功能,虽然有插件,但是移动端UI一般不能自定义,所以后来自已做了一个,直接在c#层扫描解析,UI上就可以自己发挥了。

上代码:

这个是调用zxing的脚本。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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;
  }
}

然后是封装:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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以消除镜像:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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测试可用。

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

原文链接:https://blog.csdn.net/yangxun983323204/article/details/52620091

延伸 · 阅读

精彩推荐
  • C#C#动态创建Access数据库及密码的方法

    C#动态创建Access数据库及密码的方法

    同为微软的产品,本文将讨论的是C#如何创建Access数据库,同时创建数据库密码与相关操作,希望对大家有所帮助。...

    C#教程网9322021-10-25
  • C#C#操作本地文件及保存文件到数据库的基本方法总结

    C#操作本地文件及保存文件到数据库的基本方法总结

    C#使用System.IO中的文件操作方法在Windows系统中处理本地文件相当顺手,这里我们还总结了在Oracle中保存文件的方法,嗯,接下来就来看看整理的C#操作本地文件...

    死神的丧钟6742021-11-22
  • C#C#获取进程或线程相关信息的方法

    C#获取进程或线程相关信息的方法

    这篇文章主要介绍了C#获取进程或线程相关信息的方法,涉及C#操作进程及线程的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    我心依旧7452021-10-21
  • C#C#6 null 条件运算符

    C#6 null 条件运算符

    本文主要对比C# 6 null运算符与老版本的不同,并且用代码实例测试,发现新语法性能提高,语法简化了。希望看到的同学对你有所帮助...

    C#教程网10572021-11-30
  • C#Unity3D使用右键菜单打开工程

    Unity3D使用右键菜单打开工程

    这篇文章主要为大家详细介绍了Unity3D使用右键菜单打开工程的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    星空不语5372022-07-08
  • C#Winform界面中实现菜单列表的动态个性化配置管理方法

    Winform界面中实现菜单列表的动态个性化配置管理方法

    下面小编就为大家分享一篇Winform界面中实现菜单列表的动态个性化配置管理方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    伍华聪3272022-02-13
  • C#Unity键盘WASD实现物体移动

    Unity键盘WASD实现物体移动

    这篇文章主要为大家详细介绍了Unity键盘WASD实现物体移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    weixin_3852769711922022-03-10
  • C#C# 格式化字符串的实现代码

    C# 格式化字符串的实现代码

    这篇文章主要介绍了C# 格式化字符串的实现代码,需要的朋友可以参考下...

    flyingbread10982021-12-10