经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 软件/图像 » unity » 查看文章
Unity实现多平台二维码扫描
来源:jb51  时间:2019/7/25 8:19:38  对本文有异议

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

上代码:

这个是调用zxing的脚本。

  1. using UnityEngine;
  2. using System.Collections;
  3. using ZXing;
  4. using ZXing.QrCode;
  5. public class QR {
  6. /// <summary>
  7. /// 解析二维码
  8. /// </summary>
  9. /// <param name="tex"></param>
  10. /// <returns></returns>
  11. public static string Decode(Texture2D tex) {
  12. return DecodeColData(tex.GetPixels32(), tex.width, tex.height); //通过reader解码
  13. }
  14. public static string DecodeColData(Color32[] data, int w, int h) {
  15. BarcodeReader reader = new BarcodeReader();
  16. Result result = reader.Decode(data, w, h); //通过reader解码
  17. //GC.Collect();
  18. if (result == null)
  19. return "";
  20. else {
  21. return result.Text;
  22. }
  23. }
  24. /// <summary>
  25. /// 生成二维码
  26. /// </summary>
  27. /// <param name="content"></param>
  28. /// <param name="len"></param>
  29. /// <returns></returns>
  30. public static Texture2D GetQRTexture(string content, int len = 256) {
  31. var bw = new BarcodeWriter();
  32. bw.Format = BarcodeFormat.QR_CODE;
  33. bw.Options = new ZXing.Common.EncodingOptions() {
  34. Height = len,
  35. Width = len
  36. };
  37. var cols = bw.Write(content);
  38. Texture2D t = new Texture2D(len, len);
  39. t.SetPixels32(cols);
  40. t.Apply();
  41. return t;
  42. }
  43. }

然后是封装:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System;
  4. using UnityEngine.UI;
  5. using System.Timers;
  6. /// <summary>
  7. /// 二维码解析工具
  8. /// 关键函数:
  9. /// public static QRHelper GetInst() --得到单例
  10. /// public event Action<string> OnQRScanned; --扫描回调
  11. /// public void StartCamera(int index) --启动摄像头
  12. /// public void StopCamera() --停止摄像头
  13. /// public void SetToUI(RawImage raw,int UILayoutW,int UILayoutH) --把摄像机画面设置到一个rawimage上并使它全屏显示
  14. /// </summary>
  15. public class QRHelper {
  16. public event Action<string> OnQRScanned;
  17. private static QRHelper _inst;
  18. public static QRHelper GetInst() {
  19. if (_inst == null) {
  20. _inst = new QRHelper();
  21. }
  22. return _inst;
  23. }
  24. private int reqW = 640;
  25. private int reqH = 480;
  26. private WebCamTexture webcam;
  27. Timer timer_in, timer_out;
  28. /// <summary>
  29. /// 启动摄像头
  30. /// </summary>
  31. /// <param name="index">手机后置为0,前置为1</param>
  32. public void StartCamera(int index) {
  33. StopCamera();
  34. lock (mutex) {
  35. buffer = null;
  36. tbuffer = null;
  37. }
  38. var dev = WebCamTexture.devices;
  39. webcam = new WebCamTexture(dev[index].name);
  40. webcam.requestedWidth = reqW;
  41. webcam.requestedHeight = reqH;
  42. webcam.Play();
  43. stopAnalysis = false;
  44. InitTimer();
  45. timer_in.Start();
  46. timer_out.Start();
  47. }
  48. /// <summary>
  49. /// 停止
  50. /// </summary>
  51. public void StopCamera() {
  52. if (webcam!=null) {
  53. webcam.Stop();
  54. UnityEngine.Object.Destroy(webcam);
  55. Resources.UnloadUnusedAssets();
  56. webcam = null;
  57. stopAnalysis = true;
  58. timer_in.Stop();
  59. timer_out.Start();
  60. timer_in = null;
  61. timer_out = null;
  62. }
  63. }
  64. /// <summary>
  65. /// 把摄像机画面设置到一个rawimage上并使它全屏显示
  66. /// </summary>
  67. /// <param name="raw">rawimage</param>
  68. /// <param name="UILayoutW">UI布局时的宽度</param>
  69. /// <param name="UILayoutH">UI布局时的高度</param>
  70. public void SetToUI(RawImage raw,int UILayoutW,int UILayoutH){
  71. raw.GetComponent<RectTransform>().sizeDelta = GetWH(UILayoutW,UILayoutH);
  72. int d = -1;
  73. if (webcam.videoVerticallyMirrored) {
  74. d = 1;
  75. }
  76. raw.GetComponent<RectTransform>().localRotation *= Quaternion.AngleAxis(webcam.videoRotationAngle, Vector3.back);
  77. float scaleY = webcam.videoVerticallyMirrored ? -1.0f : 1.0f;
  78. raw.transform.localScale = new Vector3(1, scaleY * 1, 0.0f);
  79. raw.texture = webcam;
  80. raw.color = Color.white;
  81. }
  82. //在考虑可能旋转的情况下计算UI的宽高
  83. private Vector2 GetWH(int UILayoutW, int UILayoutH) {
  84. int Angle = webcam.videoRotationAngle;
  85. Vector2 init = new Vector2(reqW, reqH);
  86. if ( Angle == 90 || Angle == 270 ) {
  87. var tar = init.ScaleToContain(new Vector2(UILayoutH,UILayoutW));
  88. return tar;
  89. }
  90. else {
  91. var tar = init.ScaleToContain(new Vector2(UILayoutW, UILayoutH));
  92. return tar;
  93. }
  94. }
  95. private void InitTimer() {
  96. timer_in = new Timer(500);
  97. timer_in.AutoReset = true;
  98. timer_in.Elapsed += (a,b) => {
  99. ThreadWrapper.Invoke(WriteDataBuffer);
  100. };
  101. timer_out = new Timer(900);
  102. timer_out.AutoReset = true;
  103. timer_out.Elapsed += (a,b)=>{
  104. Analysis();
  105. };
  106. }
  107. private Color32[] buffer = null;
  108. private Color32[] tbuffer = null;
  109. private object mutex = new object();
  110. private bool stopAnalysis = false;
  111. int dw, dh;
  112. private void WriteDataBuffer() {
  113. lock (mutex) {
  114. if (buffer == null && webcam!=null) {
  115. buffer = webcam.GetPixels32();
  116. dw = webcam.width;
  117. dh = webcam.height;
  118. }
  119. }
  120. }
  121. //解析二维码
  122. private void Analysis() {
  123. if (!stopAnalysis) {
  124. lock (mutex) {
  125. tbuffer = buffer;
  126. buffer = null;
  127. }
  128. if (tbuffer == null) {
  129. ;
  130. }
  131. else {
  132. string str = QR.DecodeColData(tbuffer, dw, dh);
  133. tbuffer = null;
  134. if (!str.IsNullOrEmpty() && OnQRScanned != null) {
  135. ThreadWrapper.Invoke(() => {
  136. if (OnQRScanned!=null)
  137. OnQRScanned(str);
  138. });
  139. }
  140. }
  141. }
  142. tbuffer = null;
  143. }
  144. }

调用方式如下,用了pureMVC,可能理解起来有点乱,也不能直接用于你的工程,主要看OnRegister和OnRemove里是怎么启动和停止的,以及RegQRCB、RemoveQRCB、OnQRSCcanned如何注册、移除以及响应扫描到二维码的事件的。在onregister中,由于ios上画面有镜象,所以把rawimage的scale的y置为了-1以消除镜像:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using PureMVC.Patterns;
  5. using PureMVC.Interfaces;
  6. /// <summary>
  7. /// 扫描二维码界面逻辑
  8. /// </summary>
  9. public class ScanQRMediator : Mediator {
  10. AudioProxy audio;
  11. public QRView TarView {
  12. get {
  13. return base.ViewComponent as QRView;
  14. }
  15. }
  16. public ScanQRMediator()
  17. : base("ScanQRMediator") {
  18. }
  19. string NextView = "";
  20. bool isInitOver = false;
  21. int cameraDelay = 1;
  22. public override void OnRegister() {
  23. base.OnRegister();
  24. if (Application.platform == RuntimePlatform.IPhonePlayer) {
  25. cameraDelay = 5;
  26. }
  27. else {
  28. cameraDelay = 15;
  29. }
  30. audio = AppFacade.Inst.RetrieveProxy<AudioProxy>("AudioProxy");
  31. TarView.BtnBack.onClick.AddListener(BtnEscClick);
  32. QRHelper.GetInst().StartCamera(0);
  33. TarView.WebcamContent.rectTransform.localEulerAngles = Vector3.zero;
  34. CoroutineWrapper.EXEF(cameraDelay, () => {
  35. RegQRCB();
  36. QRHelper.GetInst().SetToUI(TarView.WebcamContent, 1536, 2048);
  37. if (Application.platform == RuntimePlatform.IPhonePlayer) {
  38. TarView.WebcamContent.rectTransform.localScale = new Vector3(1, -1, 0);
  39. }
  40. isInitOver = true;
  41. });
  42. UmengStatistics.PV(TarView);
  43. //暂停背景音乐
  44. audio.SetBGActive(false);
  45. }
  46. public override void OnRemove() {
  47. base.OnRemove();
  48. TarView.BtnBack.onClick.RemoveListener(BtnEscClick);
  49. if (NextView != "UnlockView") {
  50. audio.SetBGActive(true);
  51. }
  52. NextView = "";
  53. isInitOver = false;
  54. }
  55. bool isEsc = false;
  56. void BtnEscClick() {
  57. if (isEsc || !isInitOver) {
  58. return;
  59. }
  60. isEsc = true;
  61. TarView.WebcamContent.texture = null;
  62. TarView.WebcamContent.color = Color.black;
  63. RemoveQRCB();
  64. QRHelper.GetInst().StopCamera();
  65. CoroutineWrapper.EXEF(cameraDelay, () => {
  66. isEsc = false;
  67. if (Application.platform == RuntimePlatform.IPhonePlayer) {
  68. ToUserInfoView();
  69. }
  70. else {
  71. string origin = TarView.LastArg.SGet<string>("origin");
  72. if (origin == "ARView") {
  73. ToARView();
  74. }
  75. else if (origin == "UserInfoView") {
  76. ToUserInfoView();
  77. }
  78. else {
  79. ToARView();
  80. }
  81. }
  82. });
  83. }
  84. void ToARView() {
  85. AppFacade.Inst.RemoveMediator(this.MediatorName);
  86. ViewMgr.GetInst().ShowView(TarView, "ARView", null);
  87. }
  88. void ToUserInfoView() {
  89. AppFacade.Inst.RemoveMediator(this.MediatorName);
  90. ViewMgr.GetInst().ShowView(TarView, "UserInfoView", null);
  91. var v = ViewMgr.GetInst().PeekTop();
  92. var vc = new UserInfoMediator();
  93. vc.ViewComponent = v;
  94. AppFacade.Inst.RegisterMediator(vc);
  95. }
  96. int reg = 0;
  97. void RegQRCB() {
  98. if (reg == 0) {
  99. QRHelper.GetInst().OnQRScanned += OnQRScanned;
  100. reg = 1;
  101. }
  102. }
  103. void RemoveQRCB() {
  104. if (reg == 1) {
  105. QRHelper.GetInst().OnQRScanned -= OnQRScanned;
  106. reg = 0;
  107. }
  108. }
  109. bool isQRJump = false;
  110. void OnQRScanned(string qrStr) {
  111. if (isQRJump) {
  112. return;
  113. }
  114. isQRJump = true;
  115. TarView.WebcamContent.texture = null;
  116. TarView.WebcamContent.color = Color.black;
  117. RemoveQRCB();
  118. QRHelper.GetInst().StopCamera();
  119. NextView = "UnlockView";
  120. CoroutineWrapper.EXEF(cameraDelay, () => {
  121. isQRJump = false;
  122. AppFacade.Inst.RemoveMediator(this.MediatorName);
  123. audio.PlayScanedEffect();
  124. #if YX_DEBUG
  125. Debug.Log("qr is :"+qrStr);
  126. Toast.ShowText(qrStr,1.5f);
  127. #endif
  128. ViewMgr.GetInst().ShowView(TarView, "UnlockView", HashtableEX.Construct("QRCode", qrStr, "origin", TarView.LastArg.SGet<string>("origin")));
  129. var v = ViewMgr.GetInst().PeekTop();
  130. var vc = new UnlockMediator();
  131. vc.ViewComponent = v;
  132. AppFacade.Inst.RegisterMediator(vc);
  133. });
  134. }
  135. }

最后,放上zxing.unity.dll,放在plugins里就可以了。

以上代码5.1.2测试可用。

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号