Przeglądaj źródła

udp蓝牙控制弓箭

lvjincheng 3 lat temu
rodzic
commit
8a51da2c24

+ 1 - 0
.gitignore

@@ -7,6 +7,7 @@
 /UserSettings/
 .vs/
 .vscode/
+.vsconfig
 
 # Autogenerated VS/MD solution and project files
 *.csproj

+ 266 - 371
Assets/BowArrow/Scripts/Bluetooth/BluetoothAim.cs

@@ -21,35 +21,46 @@ public class BluetoothAim : MonoBehaviour
     public static bool scanLock = false; //防止同时扫描冲突
     public static BluetoothAim ins;
 
-    void Start() {
+    void Start()
+    {
         ins = this;
         InitAutoDormancy();
+
+#if UNITY_STANDALONE_WIN
+        new GameObject("BleUDP").AddComponent<BleUDP>();
+#endif
     }
 
     void OnDestroy()
     {
-        if (bluetoothHelper != null)
-        {
-            bluetoothHelper.Disconnect();
-        }
+        DisconnectBleHelper();
     }
 
     private bool userDoConnect = false;
     private bool doConnect = false;
-    public void DoConnect() {
-        if (status == BluetoothStatusEnum.Connect) {
+    public void DoConnect()
+    {
+        if (status == BluetoothStatusEnum.Connect)
+        {
             userDoConnect = true;
             doConnect = true;
             SetStatus(BluetoothStatusEnum.Connecting);
-        } else if (status == BluetoothStatusEnum.ConnectSuccess) {
+        }
+        else if (status == BluetoothStatusEnum.ConnectSuccess)
+        {
             userDoConnect = false;
             doConnect = false;
             OnDisconnect();
-            bluetoothHelper.Disconnect();
+#if UNITY_ANDROID
+            DisconnectBleHelper();
+#elif UNITY_STANDALONE_WIN
+            BleUDP.ins.Disconnect();
+#endif
         }
     }
 
-    void OnDisconnect() {
+    void OnDisconnect()
+    {
         hasData = false;
         canConnect = true;
         SetStatus(BluetoothStatusEnum.ConnectFail);
@@ -59,21 +70,25 @@ public class BluetoothAim : MonoBehaviour
 
     void Update()
     {
-        if (userDoConnect && status == BluetoothStatusEnum.Connect) {
+        if (userDoConnect && status == BluetoothStatusEnum.Connect)
+        {
             DoConnect();
         }
         if (doConnect) Connect();
     }
 
-    void SetStatus(BluetoothStatusEnum statusValue) 
+    void SetStatus(BluetoothStatusEnum statusValue)
     {
         status = statusValue;
-        if (status == BluetoothStatusEnum.ConnectFail) {
+        if (status == BluetoothStatusEnum.ConnectFail)
+        {
             Sequence sequence = DOTween.Sequence();
             sequence.AppendInterval(2f);
-            sequence.AppendCallback(delegate() {
-                if (status == BluetoothStatusEnum.ConnectFail) {
-                    status = BluetoothStatusEnum.Connect;        
+            sequence.AppendCallback(delegate ()
+            {
+                if (status == BluetoothStatusEnum.ConnectFail)
+                {
+                    status = BluetoothStatusEnum.Connect;
                 }
             });
             sequence.SetUpdate(true);
@@ -81,6 +96,11 @@ public class BluetoothAim : MonoBehaviour
         }
     }
 
+    void DisconnectBleHelper()
+    {
+        if (bluetoothHelper != null) bluetoothHelper.Disconnect();
+    }
+
     void Connect()
     {
         if (BluetoothShoot.scanLock)
@@ -95,6 +115,15 @@ public class BluetoothAim : MonoBehaviour
         scanLock = true;
         canConnect = false;
         SetStatus(BluetoothStatusEnum.Connecting);
+#if UNITY_ANDROID
+        ConnectBleHelper();
+#elif UNITY_STANDALONE_WIN
+        ConnectBleByUDP();
+#endif
+    }
+
+    void ConnectBleHelper()
+    {
         try
         {
             BluetoothHelper.BLE = true;
@@ -107,7 +136,7 @@ public class BluetoothAim : MonoBehaviour
                 BowCamera.isTouchMode = false;
                 foreach (BluetoothHelperService service in helper.getGattServices())
                 {
-                
+
                     if (service.getName().ToLower().StartsWith("0000fff0"))
                     {
                         bluetoothService = service;
@@ -131,7 +160,8 @@ public class BluetoothAim : MonoBehaviour
                 // CallDelay(1, OpenInfrared);
                 // CallDelay(2, OpenReceiveData);
                 // CallDelay(3, RequestBattery);
-                CallDelay(2, () => {
+                CallDelay(2, () =>
+                {
                     if (status != BluetoothStatusEnum.ConnectSuccess) return;
                     InitWhenConenct();
                 });
@@ -168,11 +198,14 @@ public class BluetoothAim : MonoBehaviour
                         return;
                     }
                 }
-                if (scanCount < 3) { //如果没扫描到,则重新扫描,达到延迟提示失败的效果
+                if (scanCount < 3)
+                { //如果没扫描到,则重新扫描,达到延迟提示失败的效果
                     scanCount++;
                     scanLock = true;
                     bluetoothHelper.ScanNearbyDevices();
-                } else {
+                }
+                else
+                {
                     canConnect = true;
                     Log("没有发现设备");
                     SetStatus(BluetoothStatusEnum.ConnectFail);
@@ -184,169 +217,239 @@ public class BluetoothAim : MonoBehaviour
         }
         catch (Exception e)
         {
-            Debug.Log(e.Message);
+            Debug.LogError(e.Message);
+            Debug.LogError(e.StackTrace);
+            scanLock = false;
             canConnect = true;
+            SetStatus(BluetoothStatusEnum.ConnectFail);
             Log("请打开蓝牙");
         }
     }
 
-    #region 自动进入/退出休眠状态, 这里做程指令发送队列,为了控制连续发送指令的间隔,避免硬件收不到或处理不过来
-        class CmdToSend {
-            public string[] cmds;
-            public Action onComplete;
-            public Func<bool> canDo; 
-            public CmdToSend(string[] cmds, Action onComplete, Func<bool> canDo) {
-                this.cmds = cmds; 
-                this.onComplete = onComplete;
-                this.canDo = canDo;
-            }
+    void ConnectBleByUDP()
+    {
+        try
+        {
+            BleUDP.ins.OnConnected = () =>
+            {
+                Log("连接成功\n" + deviceName);
+                SetStatus(BluetoothStatusEnum.ConnectSuccess);
+                BowCamera.isTouchMode = false;
+                InitWhenConenct();
+            };
+            BleUDP.ins.OnConnectionFailed = () =>
+            {
+                Log("连接失败\n" + deviceName);
+                OnDisconnect();
+            };
+            BleUDP.ins.OnCharacteristicChanged = (byte[] value) =>
+            {
+                if (!hasData) hasDataTime = JC.CS.Utility.GetTimestamp();
+                hasData = true;
+                byte[] bytes = value;
+                // Log(String.Join(",", bytes));
+                BluetoothClient.UploadData(0, bytes);
+                if (AimHandler.ins)
+                {
+                    AimHandler.ins.OnDataReceived(bytes);
+                }
+            };
+            BleUDP.ins.OnScanEnded = () =>
+            {
+                scanLock = false;
+                deviceName = targetDeviceName;
+                BleUDP.ins.Connect();
+                Log("发现设备\n" + deviceName);
+            };
+
+            BleUDP.ins.ScanNearbyDevices();
         }
-        Queue<CmdToSend> cmdWaitingList = new Queue<CmdToSend>();
-        bool isSendCmdLocked = false;
-        bool canAutoDormancy = false;
-        bool isStartUp = false;
-        JC.CS.CountLocker needModularAwake = new JC.CS.CountLocker();
-        void CheckAndStartUp() {
-            if (needModularAwake.IsLocked()) {
-                StartUp();
-            } else {
-                Dormancy();
-            }
+        catch (Exception e)
+        {
+            Debug.LogError(e.Message);
+            Debug.LogError(e.StackTrace);
+            scanLock = false;
+            canConnect = true;
+            SetStatus(BluetoothStatusEnum.ConnectFail);
         }
-        void InitAutoDormancy() {
-            // GlobalEventCenter.ins.onGameSceneLoad += () => { 
-            //     needModularAwake.Lock(); 
-            //     CheckAndStartUp();
-            // };
-            // GlobalEventCenter.ins.onGameSceneDestroy += () => { 
-            //     needModularAwake.Unlock(); 
-            //     CheckAndStartUp();
-            // };
-            // GlobalEventCenter.ins.onSimulateMouseAwakeChanged += (waked) => {
-            //     if (waked) needModularAwake.Lock();
-            //     else needModularAwake.Unlock();;
-            //     CheckAndStartUp();
-            // };
-            // GlobalEventCenter.ins.onDeviceCalibrateViewAwakeChanged += (waked) => {
-            //     if (waked) needModularAwake.Lock();
-            //     else needModularAwake.Unlock();;
-            //     CheckAndStartUp();
-            // };
-            //暂时关闭自动休眠,默认是需要模块保持激活
-            needModularAwake.Lock(); 
+    }
+
+    #region 自动进入/退出休眠状态, 这里做程指令发送队列,为了控制连续发送指令的间隔,避免硬件收不到或处理不过来
+    class CmdToSend
+    {
+        public string[] cmds;
+        public Action onComplete;
+        public Func<bool> canDo;
+        public CmdToSend(string[] cmds, Action onComplete, Func<bool> canDo)
+        {
+            this.cmds = cmds;
+            this.onComplete = onComplete;
+            this.canDo = canDo;
         }
-        void InitWhenConenct() { 
-            canAutoDormancy = true;
-            List<string> cmds = new List<string>();
-            cmds.Add("b"); //确保开启stm32
-            cmds.Add("b"); //获取初始电量
-            cmds.Add("1"); //开启发送逻辑
-            Action onComplete = null;
-            if (needModularAwake.IsLocked()) {
-                cmds.Add("w"); //红外灯开启
-                cmds.Add("3"); //九轴开启
-                onComplete = () => {
-                    isStartUp = true;
-                };
-            } else {
-                cmds.Add("s"); //红外灯关闭
-                cmds.Add("S"); //Stm32关闭
-                cmds.Add("4"); //九轴关闭
-                onComplete = () => {
-                    isStartUp = false;
-                };
-            }
-            SendCDM(null, onComplete, cmds.ToArray());
+    }
+    Queue<CmdToSend> cmdWaitingList = new Queue<CmdToSend>();
+    bool isSendCmdLocked = false;
+    bool canAutoDormancy = false;
+    bool isStartUp = false;
+    JC.CS.CountLocker needModularAwake = new JC.CS.CountLocker();
+    void CheckAndStartUp()
+    {
+        if (needModularAwake.IsLocked())
+        {
+            StartUp();
         }
-        void DestroyWhenDisconenct() {
-            canAutoDormancy = false;
-            sendCMD_CheckAndDoStop(null);
-
+        else
+        {
+            Dormancy();
         }
-        //启动
-        void StartUp() {
-            SendCDM(() => {
-                return !isStartUp;
-            }, () => {
+    }
+    void InitAutoDormancy()
+    {
+        // GlobalEventCenter.ins.onGameSceneLoad += () => { 
+        //     needModularAwake.Lock(); 
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onGameSceneDestroy += () => { 
+        //     needModularAwake.Unlock(); 
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onSimulateMouseAwakeChanged += (waked) => {
+        //     if (waked) needModularAwake.Lock();
+        //     else needModularAwake.Unlock();;
+        //     CheckAndStartUp();
+        // };
+        // GlobalEventCenter.ins.onDeviceCalibrateViewAwakeChanged += (waked) => {
+        //     if (waked) needModularAwake.Lock();
+        //     else needModularAwake.Unlock();;
+        //     CheckAndStartUp();
+        // };
+        //暂时关闭自动休眠,默认是需要模块保持激活
+        needModularAwake.Lock();
+    }
+    void InitWhenConenct()
+    {
+        canAutoDormancy = true;
+        List<string> cmds = new List<string>();
+        cmds.Add("b"); //确保开启stm32
+        cmds.Add("b"); //获取初始电量
+        cmds.Add("1"); //开启发送逻辑
+        Action onComplete = null;
+        if (needModularAwake.IsLocked())
+        {
+            cmds.Add("w"); //红外灯开启
+            cmds.Add("3"); //九轴开启
+            onComplete = () =>
+            {
                 isStartUp = true;
-            }, "b", "w", "3");
+            };
         }
-        //休眠
-        void Dormancy() {
-            SendCDM(() => {
-                return isStartUp;
-            }, () => {
+        else
+        {
+            cmds.Add("s"); //红外灯关闭
+            cmds.Add("S"); //Stm32关闭
+            cmds.Add("4"); //九轴关闭
+            onComplete = () =>
+            {
                 isStartUp = false;
-            }, "4", "s", "S");
+            };
         }
-        void SendCDM(Func<bool> canDo, Action onComplete, params string[] cmds) {
-            CmdToSend cmdToSend = new CmdToSend(cmds, onComplete, canDo);
-            if (isSendCmdLocked) {
-                cmdWaitingList.Enqueue(cmdToSend);
-                return;
-            }
-            sendCMD_NotCheck(cmdToSend);
-        }   
-        void sendCMD_NotCheck(CmdToSend cmdToSend) {
-            if (cmdToSend.canDo != null && !cmdToSend.canDo.Invoke()) {
-                sendCMD_CheckNext();
-                return;
-            }
-            isSendCmdLocked = true;
-            Sequence sequence = DOTween.Sequence();
-            sequence.PrependInterval(0.3f);
-            foreach (var cmd in cmdToSend.cmds) {
-                sequence.AppendCallback(() => {
-                    bool stopped = sendCMD_CheckAndDoStop(sequence);
-                    if (!stopped) WriteData(cmd);
-                });
-                sequence.AppendInterval(0.5f);
-            }
-            sequence.AppendCallback(() => {
-                bool stopped = sendCMD_CheckAndDoStop(sequence);
-                if (!stopped) {
-                    isSendCmdLocked = false;
-                    cmdToSend.onComplete?.Invoke();
-                    sendCMD_CheckNext();
-                }
-            });
-            sequence.SetUpdate(true);
+        SendCDM(null, onComplete, cmds.ToArray());
+    }
+    void DestroyWhenDisconenct()
+    {
+        canAutoDormancy = false;
+        sendCMD_CheckAndDoStop(null);
+
+    }
+    //启动
+    void StartUp()
+    {
+        SendCDM(() =>
+        {
+            return !isStartUp;
+        }, () =>
+        {
+            isStartUp = true;
+        }, "b", "w", "3");
+    }
+    //休眠
+    void Dormancy()
+    {
+        SendCDM(() =>
+        {
+            return isStartUp;
+        }, () =>
+        {
+            isStartUp = false;
+        }, "4", "s", "S");
+    }
+    void SendCDM(Func<bool> canDo, Action onComplete, params string[] cmds)
+    {
+        CmdToSend cmdToSend = new CmdToSend(cmds, onComplete, canDo);
+        if (isSendCmdLocked)
+        {
+            cmdWaitingList.Enqueue(cmdToSend);
+            return;
         }
-        void sendCMD_CheckNext() {
-            if (cmdWaitingList.Count <= 0) return;
-            CmdToSend cmdToSend = cmdWaitingList.Dequeue();
-            sendCMD_NotCheck(cmdToSend);
+        sendCMD_NotCheck(cmdToSend);
+    }
+    void sendCMD_NotCheck(CmdToSend cmdToSend)
+    {
+        if (cmdToSend.canDo != null && !cmdToSend.canDo.Invoke())
+        {
+            sendCMD_CheckNext();
+            return;
         }
-        bool sendCMD_CheckAndDoStop(Sequence sequence) {
-            if (canAutoDormancy) return false;
-            isStartUp = false;
-            isSendCmdLocked = false;
-            cmdWaitingList.Clear();
-            if (sequence != null) sequence.Kill();
-            return true;
+        isSendCmdLocked = true;
+        Sequence sequence = DOTween.Sequence();
+        sequence.PrependInterval(0.3f);
+        foreach (var cmd in cmdToSend.cmds)
+        {
+            sequence.AppendCallback(() =>
+            {
+                bool stopped = sendCMD_CheckAndDoStop(sequence);
+                if (!stopped) WriteData(cmd);
+            });
+            sequence.AppendInterval(0.5f);
         }
-    #endregion
-
-
-    void OpenInfrared()
+        sequence.AppendCallback(() =>
+        {
+            bool stopped = sendCMD_CheckAndDoStop(sequence);
+            if (!stopped)
+            {
+                isSendCmdLocked = false;
+                cmdToSend.onComplete?.Invoke();
+                sendCMD_CheckNext();
+            }
+        });
+        sequence.SetUpdate(true);
+    }
+    void sendCMD_CheckNext()
     {
-        WriteData("1");
-        Log("红外线准备完成\n" + deviceName);
+        if (cmdWaitingList.Count <= 0) return;
+        CmdToSend cmdToSend = cmdWaitingList.Dequeue();
+        sendCMD_NotCheck(cmdToSend);
     }
-
-    void OpenReceiveData()
+    bool sendCMD_CheckAndDoStop(Sequence sequence)
     {
-        WriteData("3");
-        Log("瞄准模块准备完成\n" + deviceName);
+        if (canAutoDormancy) return false;
+        isStartUp = false;
+        isSendCmdLocked = false;
+        cmdWaitingList.Clear();
+        if (sequence != null) sequence.Kill();
+        return true;
     }
+    #endregion
 
-    public void RequestBattery() {
+    public void RequestBattery()
+    {
         if (!isStartUp) return;
         if (isSendCmdLocked) return;
         WriteData("b");
     }
 
-    public void ReplyInfraredShoot() {
+    public void ReplyInfraredShoot()
+    {
         if (isSendCmdLocked) return;
         WriteData("I");
     }
@@ -360,230 +463,22 @@ public class BluetoothAim : MonoBehaviour
 
     public void WriteData(string data)
     {
+#if UNITY_ANDROID
         if (DebugDeviceCMD.ins) DebugDeviceCMD.ins.ShowCMD(data);
         BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristicWrite.getName());
         ch.setService(bluetoothService.getName());
         bluetoothHelper.WriteCharacteristic(ch, data);
+#elif UNITY_STANDALONE_WIN
+        BleUDP.ins.SendMsg(data);
+#endif
+
     }
 
     void Log(string text)
     {
-        if (textUI) 
+        if (textUI)
         {
             textUI.text = text;
         }
     }
-}
-// public class BluetoothAim : MonoBehaviour
-// {
-//     BluetoothHelper bluetoothHelper;
-//     BluetoothHelperCharacteristic characteristicWrite;
-//     BluetoothHelperService bluetoothService;
-//     string targetDeviceName = "Bbow_20210501";
-//     string deviceName = "";
-//     bool canConnect = true;
-//     [SerializeField] Text textUI;
-//     public BluetoothStatusEnum status = BluetoothStatusEnum.Connect;
-//     public bool hasData = false;
-//     public long hasDataTime;
-//     public static bool scanLock = false; //防止同时扫描冲突
-//     public static BluetoothAim ins;
-
-//     void Start() {
-//         ins = this;
-//     }
-
-//     void OnDestroy()
-//     {
-//         if (bluetoothHelper != null)
-//         {
-//             bluetoothHelper.Disconnect();
-//         }
-//     }
-
-//     private bool userDoConnect = false;
-//     private bool doConnect = false;
-//     public void DoConnect() {
-//         if (status == BluetoothStatusEnum.Connect) {
-//             userDoConnect = true;
-//             doConnect = true;
-//             SetStatus(BluetoothStatusEnum.Connecting);
-//         } else if (status == BluetoothStatusEnum.ConnectSuccess) {
-//             userDoConnect = false;
-//             doConnect = false;
-//             OnDisconnect();
-//             bluetoothHelper.Disconnect();
-//         }
-//     }
-
-//     void OnDisconnect() {
-//         hasData = false;
-//         canConnect = true;
-//         SetStatus(BluetoothStatusEnum.ConnectFail);
-//         BowCamera.isTouchMode = true;
-//     }
-
-//     void Update()
-//     {
-//         if (userDoConnect && status == BluetoothStatusEnum.Connect) {
-//             DoConnect();
-//         }
-//         if (doConnect) Connect();
-//     }
-
-//     void SetStatus(BluetoothStatusEnum statusValue) 
-//     {
-//         status = statusValue;
-//         if (status == BluetoothStatusEnum.ConnectFail) {
-//             Sequence sequence = DOTween.Sequence();
-//             sequence.AppendInterval(2f);
-//             sequence.AppendCallback(delegate() {
-//                 if (status == BluetoothStatusEnum.ConnectFail) {
-//                     status = BluetoothStatusEnum.Connect;        
-//                 }
-//             });
-//             sequence.SetUpdate(true);
-//             DeviceReconnectView.Show();
-//         }
-//     }
-
-//     void Connect()
-//     {
-//         if (BluetoothShoot.scanLock)
-//         {
-//             return;
-//         }
-//         if (!canConnect)
-//         {
-//             return;
-//         }
-//         doConnect = false;
-//         scanLock = true;
-//         canConnect = false;
-//         SetStatus(BluetoothStatusEnum.Connecting);
-//         try
-//         {
-//             BluetoothHelper.BLE = true;
-//             bluetoothHelper = BluetoothHelper.GetNewInstance();
-
-//             bluetoothHelper.OnConnected += (BluetoothHelper helper) =>
-//             {
-//                 Log("连接成功\n" + helper.getDeviceName());
-//                 SetStatus(BluetoothStatusEnum.ConnectSuccess);
-//                 BowCamera.isTouchMode = false;
-//                 foreach (BluetoothHelperService service in helper.getGattServices())
-//                 {
-                
-//                     if (service.getName().ToLower().StartsWith("0000fff0"))
-//                     {
-//                         bluetoothService = service;
-
-//                         foreach (BluetoothHelperCharacteristic characteristic in service.getCharacteristics())
-//                         {
-//                             if (characteristic.getName().ToLower().StartsWith("0000fff2"))
-//                             {
-//                                 characteristicWrite = characteristic;
-//                             }
-//                             else if (characteristic.getName().ToLower().StartsWith("0000fff1"))
-//                             {
-
-//                                 BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristic.getName());
-//                                 ch.setService(bluetoothService.getName());
-//                                 bluetoothHelper.Subscribe(ch);
-//                             }
-//                         }
-//                     }
-//                 }
-//                 CallDelay(1, OpenInfrared);
-//                 CallDelay(2, OpenReceiveData);
-//                 CallDelay(3, RequestBattery);
-//             };
-//             bluetoothHelper.OnConnectionFailed += (BluetoothHelper helper) =>
-//             {
-//                 Log("连接失败\n" + helper.getDeviceName());
-//                 OnDisconnect();
-//             };
-//             bluetoothHelper.OnCharacteristicChanged += (helper, value, characteristic) =>
-//             {
-//                 if (!hasData) hasDataTime = JC.CS.Utility.GetTimestamp();
-//                 hasData = true;
-//                 byte[] bytes = value;
-//                 // Log(String.Join(",", bytes));
-//                 BluetoothClient.UploadData(0, bytes);
-//                 if (AimHandler.ins)
-//                 {
-//                     AimHandler.ins.OnDataReceived(bytes);
-//                 }
-//             };
-//             bluetoothHelper.OnScanEnded += (BluetoothHelper helper, LinkedList<BluetoothDevice> nearbyDevices) =>
-//             {
-//                 scanLock = false;
-//                 foreach (BluetoothDevice device in nearbyDevices)
-//                 {
-//                     if (device.DeviceName == targetDeviceName)
-//                     {
-//                         deviceName = device.DeviceName;
-//                         bluetoothHelper.setDeviceName(deviceName);
-//                         bluetoothHelper.Connect();
-//                         Log("发现设备\n" + device.DeviceName);
-//                         return;
-//                     }
-//                 }
-//                 canConnect = true;
-//                 Log("没有发现设备");
-//                 SetStatus(BluetoothStatusEnum.ConnectFail);
-//             };
-
-//             bluetoothHelper.ScanNearbyDevices();
-//             Log("正在扫描设备");
-//         }
-//         catch (Exception e)
-//         {
-//             Debug.Log(e.Message);
-//             canConnect = true;
-//             Log("请打开蓝牙");
-//         }
-//     }
-
-//     void OpenInfrared()
-//     {
-//         WriteData("1");
-//         Log("红外线准备完成\n" + deviceName);
-//     }
-
-//     void OpenReceiveData()
-//     {
-//         WriteData("3");
-//         Log("瞄准模块准备完成\n" + deviceName);
-//     }
-
-//     public void RequestBattery() {
-//         WriteData("b");
-//     }
-
-//     public void ReplyInfraredShoot() {
-//         WriteData("I");
-//     }
-
-//     void CallDelay(float delayTime, TweenCallback callback)
-//     {
-//         Sequence sequence = DOTween.Sequence();
-//         sequence.PrependInterval(delayTime).AppendCallback(callback);
-//         sequence.SetUpdate(true);
-//     }
-
-//     public void WriteData(string data)
-//     {
-//         BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristicWrite.getName());
-//         ch.setService(bluetoothService.getName());
-//         bluetoothHelper.WriteCharacteristic(ch, data);
-//     }
-
-//     void Log(string text)
-//     {
-//         if (textUI) 
-//         {
-//             textUI.text = text;
-//         }
-//     }
-// }
+}

+ 133 - 69
Assets/BowArrow/Scripts/Game/BowCamera.cs

@@ -6,16 +6,20 @@ public class BowCamera : MonoBehaviour
 {
     //相机组件
     Camera _cameraComp;
-    Camera cameraComp {
-        get {
+    Camera cameraComp
+    {
+        get
+        {
             if (!_cameraComp) _cameraComp = GetComponent<Camera>();
             return _cameraComp;
         }
     }
     //控制的手臂弓
     ArmBow _armBow;
-    ArmBow armBow {
-        get {
+    ArmBow armBow
+    {
+        get
+        {
             if (!_armBow) _armBow = GetComponentInChildren<ArmBow>();
             return _armBow;
         }
@@ -26,79 +30,96 @@ public class BowCamera : MonoBehaviour
     JC.Unity.TouchChecker touchChecker = new JC.Unity.TouchChecker();
     //触摸模式开关
     private static bool _isTouchMode = true;
-    public static bool isTouchMode {
-        get {
+    public static bool isTouchMode
+    {
+        get
+        {
             if (CommonConfig.isReleaseVersion) return false;
             return _isTouchMode;
         }
-        set {
+        set
+        {
             _isTouchMode = value;
         }
     }
     //左右转动范围限制
-    float[] limitRangeRotateY = {-80, 80};
+    float[] limitRangeRotateY = { -80, 80 };
     //上下转动范围限制
-    float[] limitRangeRotateX = {-80, 80};
+    float[] limitRangeRotateX = { -80, 80 };
     //禁止逻辑,只用于同步状态和渲染,目前用于联机
     [NonSerialized] public bool banLogic = false;
     private static BowCamera _ins;
-    public static BowCamera ins {
-        get {
-            if (!_ins) {
+    public static BowCamera ins
+    {
+        get
+        {
+            if (!_ins)
+            {
                 _ins = GameObject.FindObjectOfType<BowCamera>();
             }
             return _ins;
         }
     }
 
-    void Awake() {
+    void Awake()
+    {
         _ins = this;
         localEulerAngles = transform.localEulerAngles;
         RecordDefaultCameraFieldOfView();
-        if (UserSettings.ins.bowCameraFixed && !CommonConfig.isReleaseVersion) {
+        if (UserSettings.ins.bowCameraFixed && !CommonConfig.isReleaseVersion)
+        {
             bowCameraFixed = new BowCameraFixed(this);
         }
     }
 
-    void Start() {
-        touchChecker.onMoved += delegate(Touch t, bool isOnUI) {
+    void Start()
+    {
+        touchChecker.onMoved += delegate (Touch t, bool isOnUI)
+        {
             if (banLogic) return;
             if (isOnUI) return;
             //触摸控制镜头和拉弓射箭
             this.localEulerAngles.x = Mathf.Clamp(this.localEulerAngles.x - t.deltaPosition.y * Time.deltaTime * 5, limitRangeRotateX[0], limitRangeRotateX[1]);
-            this.localEulerAngles.y = Mathf.Clamp(this.localEulerAngles.y + t.deltaPosition.x * Time.deltaTime * 5, limitRangeRotateY[0], limitRangeRotateY[1]);   
-            this.transform.localEulerAngles = this.localEulerAngles; 
+            this.localEulerAngles.y = Mathf.Clamp(this.localEulerAngles.y + t.deltaPosition.x * Time.deltaTime * 5, limitRangeRotateY[0], limitRangeRotateY[1]);
+            this.transform.localEulerAngles = this.localEulerAngles;
         };
-        touchChecker.onEnded += delegate(Touch t, bool isOnUI) {
+        touchChecker.onEnded += delegate (Touch t, bool isOnUI)
+        {
             if (banLogic) return;
             if (!isOnUI) armBow.ADS_fire();
         };
     }
 
     void Update()
-    {   
+    {
         //更新相机视野
-        if (cameraComp && !banCameraFieldOfView) {
+        if (cameraComp && !banCameraFieldOfView)
+        {
             cameraComp.fieldOfView = cameraFieldOfView;
         }
 
         if (banLogic) return;
 
         //满足以下条件则阻止控制输入
-        if (GameMgr.ins.gameOver) {
-           return;
+        if (GameMgr.ins.gameOver)
+        {
+            return;
         }
 
-        if (GameMgr.debugInEditor) {
+        if (GameMgr.debugInEditor)
+        {
             //鼠标控制镜头和拉弓射箭
             this.localEulerAngles.x = Mathf.Clamp(this.localEulerAngles.x - 2f * Input.GetAxis("Mouse Y"), limitRangeRotateX[0], limitRangeRotateX[1]);
             this.localEulerAngles.y = Mathf.Clamp(this.localEulerAngles.y + 2f * Input.GetAxis("Mouse X"), limitRangeRotateY[0], limitRangeRotateY[1]);
-            this.transform.localEulerAngles = this.localEulerAngles; 
+            this.transform.localEulerAngles = this.localEulerAngles;
             if (EventSystem.current.IsPointerOverGameObject()) return;
         }
-        else if (isTouchMode) {
+        else if (isTouchMode)
+        {
             touchChecker.Update();
-        } else {
+        }
+        else
+        {
             if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) return;
             //需要-镜头看向九轴姿态虚拟节点
             needLookAtPoint = true;
@@ -106,31 +127,44 @@ public class BowCamera : MonoBehaviour
     }
 
     //需要-镜头看向九轴姿态虚拟节点?
-    bool needLookAtPoint = false; 
+    bool needLookAtPoint = false;
     //镜头旋转转换比值
     float[] _bowRotateConvertRate = null;
-    float bowRotateConvertRate {
-        get {
-            if (_bowRotateConvertRate == null) {
-                _bowRotateConvertRate = new float[]{ UserSettings.ins.bowRotateConvert.GetRate() };
+    float bowRotateConvertRate
+    {
+        get
+        {
+            if (_bowRotateConvertRate == null)
+            {
+                _bowRotateConvertRate = new float[] { UserSettings.ins.bowRotateConvert.GetRate() };
             }
             return _bowRotateConvertRate[0];
         }
     }
-    void LateUpdate() {
-        if (needLookAtPoint) {
+    void LateUpdate()
+    {
+#if UNITY_STANDALONE_WIN
+        if (BleUDP.ins && BleUDP.ins.bluetoothStatusEnum == BluetoothStatusEnum.ConnectSuccess)
+        {
+            needLookAtPoint = true;
+        }
+#endif
+        if (needLookAtPoint)
+        {
             needLookAtPoint = false;
             //镜头看向九轴姿态虚拟节点
             this.transform.LookAt(CameraToLook.ins.point);
             // if (BowQuatDebug.ins) BowQuatDebug.ins.ShowRealBowQuat(this.transform.localEulerAngles); 
-            if (!CommonConfig.isReleaseVersion) {
+            if (!CommonConfig.isReleaseVersion)
+            {
                 //镜头旋转比值转换
                 Vector3 localAngles = this.transform.localEulerAngles;
                 localAngles.x = Mathf.Clamp((localAngles.x > 180 ? localAngles.x - 360 : localAngles.x) * bowRotateConvertRate,
                     limitRangeRotateX[0], limitRangeRotateX[1]);
                 localAngles.y = Mathf.Clamp((localAngles.y > 180 ? localAngles.y - 360 : localAngles.y) * bowRotateConvertRate,
                     limitRangeRotateY[0], limitRangeRotateY[1]);
-                if (bowCameraFixed != null) {
+                if (bowCameraFixed != null)
+                {
                     localAngles = bowCameraFixed.LimitBowAngle(localAngles);
                 }
                 this.transform.localEulerAngles = localAngles;
@@ -146,23 +180,27 @@ public class BowCamera : MonoBehaviour
     //视野值记录
     float cameraFieldOfView = 60;
     [NonSerialized] public float defaultCameraFieldOfView = 60;
-    private void RecordDefaultCameraFieldOfView() {
+    private void RecordDefaultCameraFieldOfView()
+    {
         defaultCameraFieldOfView = cameraComp.fieldOfView;
         cameraFieldOfView = defaultCameraFieldOfView;
     }
     //禁止相机视野改变
     [NonSerialized] public bool banCameraFieldOfView = false;
-    
-    public void SetCameraFieldOfView(float value) {
+
+    public void SetCameraFieldOfView(float value)
+    {
         cameraComp.fieldOfView = value;
     }
 
-    public void SetCameraFieldOfViewRecord(float value) {
+    public void SetCameraFieldOfViewRecord(float value)
+    {
         cameraFieldOfView = value;
     }
 
     //拉弓时的相机视野值变化
-    public void updateFollowPullBow() {
+    public void updateFollowPullBow()
+    {
         // if (cameraFieldOfView > 40) {
         //     cameraFieldOfView -= 20 * Time.deltaTime;
         // } else {
@@ -171,7 +209,8 @@ public class BowCamera : MonoBehaviour
     }
 
     //松开拉弓时的相机视野值变化
-    public void updateGiveUpPullBow() {
+    public void updateGiveUpPullBow()
+    {
         // if (cameraFieldOfView < 60) {
         //     cameraFieldOfView += 20 * Time.deltaTime;
         // } else {
@@ -182,40 +221,54 @@ public class BowCamera : MonoBehaviour
     // 2022-04-28
     // ------ 添加固定镜头选项后,新增的API ------
     bool isArrowFollowing = false;
-    public void SetArrowFollowing(bool value) {
+    public void SetArrowFollowing(bool value)
+    {
         isArrowFollowing = value;
         cameraComp.enabled = !isArrowFollowing;
         AutoSwitchCamera();
     }
     bool isScaleAimDisplaying = false;
-    public void SetScaleAimDisplaying(bool value) {
+    public void SetScaleAimDisplaying(bool value)
+    {
         isScaleAimDisplaying = value;
         AutoSwitchCamera();
     }
 
-    void AutoSwitchCamera() {
-        if (bowCameraFixed == null) {
+    void AutoSwitchCamera()
+    {
+        if (bowCameraFixed == null)
+        {
             cameraComp.enabled = !isArrowFollowing;
-        } else {
+        }
+        else
+        {
             bowCameraFixed.gameObject.SetActive(!isScaleAimDisplaying && !isArrowFollowing);
             cameraComp.enabled = isScaleAimDisplaying && !isArrowFollowing;
         }
     }
 
-    public Camera GetRenderCamera() {
-        if (bowCameraFixed == null) {
+    public Camera GetRenderCamera()
+    {
+        if (bowCameraFixed == null)
+        {
             return cameraComp;
-        } else {
-            if (bowCameraFixed.gameObject.activeSelf) {
+        }
+        else
+        {
+            if (bowCameraFixed.gameObject.activeSelf)
+            {
                 return bowCameraFixed.camera;
-            } else {
+            }
+            else
+            {
                 return cameraComp;
             }
         }
     }
 
     public BowCameraFixed bowCameraFixed = null;
-    public class BowCameraFixed {
+    public class BowCameraFixed
+    {
         public GameObject gameObject;
         public Transform transform;
         public Camera camera;
@@ -225,7 +278,8 @@ public class BowCamera : MonoBehaviour
         private Camera targetCamera;
         private UnityStandardAssets.ImageEffects.Blur targetBlur;
 
-        public BowCameraFixed(BowCamera bowCamera) {
+        public BowCameraFixed(BowCamera bowCamera)
+        {
             this.bowCamera = bowCamera;
             gameObject = new GameObject("BowCameraFixed");
             transform = gameObject.transform;
@@ -242,7 +296,8 @@ public class BowCamera : MonoBehaviour
             camera.renderingPath = targetCamera.renderingPath;
             //复制Blur组件
             targetBlur = bowCamera.GetComponent<UnityStandardAssets.ImageEffects.Blur>();
-            if (targetBlur) {
+            if (targetBlur)
+            {
                 blur = gameObject.AddComponent<UnityStandardAssets.ImageEffects.Blur>();
                 blur.enabled = targetBlur.enabled;
                 blur.blurShader = targetBlur.blurShader;
@@ -258,17 +313,21 @@ public class BowCamera : MonoBehaviour
             bowCamera.onAfterLateUpdate += LateUpdate;
             //切换镜头
             bowCamera.AutoSwitchCamera();
-            
+
             InitForLimitBound();
-        } 
+        }
 
-        void LateUpdate() {
-            if (gameObject.activeSelf) {
+        void LateUpdate()
+        {
+            if (gameObject.activeSelf)
+            {
                 CrossHair.ins.UpdatePostionWhenFixedCamera();
             }
-            if (blur) {
+            if (blur)
+            {
                 blur.enabled = targetBlur.enabled;
-                if (blur.enabled) {
+                if (blur.enabled)
+                {
                     blur.blurShader = targetBlur.blurShader;
                     blur.blurSpread = targetBlur.blurSpread;
                     blur.iterations = targetBlur.iterations;
@@ -277,16 +336,19 @@ public class BowCamera : MonoBehaviour
         }
 
         //边界限制
-        float[] rangeRotateY = {-80, 80};
+        float[] rangeRotateY = { -80, 80 };
         float rangeRotateX = 25;
         Vector3 vecF;
         Vector3 vecU;
         public int outBoundIndex = -1; //-1为未出界
-        void InitForLimitBound() {
-            for (int i = (int)rangeRotateY[0]; i < 0; i++) {
+        void InitForLimitBound()
+        {
+            for (int i = (int)rangeRotateY[0]; i < 0; i++)
+            {
                 Vector3 pos = transform.position + Quaternion.AngleAxis(i, Vector3.up) * transform.forward;
                 pos = camera.WorldToViewportPoint(pos);
-                if (pos.x >= 0) {
+                if (pos.x >= 0)
+                {
                     rangeRotateY[0] = i;
                     rangeRotateY[1] = -i - 4;
                     break;
@@ -296,9 +358,10 @@ public class BowCamera : MonoBehaviour
             vecF = Quaternion.AngleAxis(rangeRotateX, Vector3.right) * Vector3.forward;
             vecU = Quaternion.AngleAxis(rangeRotateX, Vector3.right) * Vector3.up;
         }
-        public Vector3 LimitBowAngle(Vector3 outAngle) {
-            float angleY = outAngle.y; 
-            float angleX = outAngle.x; 
+        public Vector3 LimitBowAngle(Vector3 outAngle)
+        {
+            float angleY = outAngle.y;
+            float angleX = outAngle.x;
             outAngle.y = Mathf.Clamp(angleY, rangeRotateY[0], rangeRotateY[1]);
             Vector3 vec = Quaternion.AngleAxis(outAngle.y, vecU) * vecF;
             float rx = (float)(Math.Asin(vec.y) / Math.PI * 180) * (angleX < 0 ? 1 : -1);
@@ -307,7 +370,8 @@ public class BowCamera : MonoBehaviour
             else if (angleX < -rangeRotateX) outBoundIndex = 2;
             else if (angleX > rangeRotateX) outBoundIndex = 3;
             else outBoundIndex = -1;
-            if (Mathf.Abs(angleX) > Mathf.Abs(rx)) {
+            if (Mathf.Abs(angleX) > Mathf.Abs(rx))
+            {
                 outAngle.x = rx;
             }
             //因为Vector3是struct,传递给函数是值传递而非引用传递

+ 115 - 23
Assets/Test9Axis/BleUDP.cs

@@ -9,25 +9,36 @@ using System.Threading;
 
 public class BleUDP : MonoBehaviour
 {
-    string localIP = "127.0.0.1";
-    int myPort = 8001;
-    int targetPort = 8000;
-    Socket client;
-    static BleUDP ins;
+    public static BleUDP ins; //单例记录
 
-    void Start()
+    readonly string localIP = "127.0.0.1"; //本地IP
+    readonly int myPort = 8001; //自身的注册端口
+    readonly int targetPort = 8000; //发消息的目标端口
+    Socket client; //UDP对象
+
+    float noneMsgTime = 0; //多久没收到字节消息了
+    Queue<byte[]> byteQueue = new Queue<byte[]>(); //接收信息的线程把字节信息放这里
+    Queue<byte[]> byteMainQueue = new Queue<byte[]>(); //主线程从byteQueue中取出数据后放在这里,供主线程update使用
+
+    public Action OnConnected;
+    public Action OnConnectionFailed;
+    public Action<byte[]> OnCharacteristicChanged;
+    public Action OnScanEnded;
+
+    [NonSerialized] public BluetoothStatusEnum bluetoothStatusEnum = BluetoothStatusEnum.Connect;
+
+    void Awake()
     {
-        if (ins != null)
+        if (ins)
         {
-            DontDestroyOnLoad(this);
+            Destroy(this.gameObject);
             return;
         }
         ins = this;
+        DontDestroyOnLoad(this.gameObject);
 
         client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-        client.Bind(new IPEndPoint(IPAddress.Parse(localIP), myPort));               
-        Thread threadSendMsg = new Thread(sendMsg);
-        threadSendMsg.Start();                          
+        client.Bind(new IPEndPoint(IPAddress.Parse(localIP), myPort));
         Thread threadReciveMsg = new Thread(ReciveMsg);
         threadReciveMsg.Start();
     }
@@ -38,31 +49,59 @@ public class BleUDP : MonoBehaviour
         client.Close();
     }
 
-    Queue<byte[]> byteQueue = new Queue<byte[]>();
     void Update()
     {
-        byte[] bytes = null;
         lock (byteQueue)
         {
-            if (byteQueue.Count > 0)
+            while (byteQueue.Count > 0)
             {
-                bytes = byteQueue.Dequeue();
+                byteMainQueue.Enqueue(byteQueue.Dequeue());
             }
         }
-        if (bytes != null)
+        if (bluetoothStatusEnum == BluetoothStatusEnum.Connecting)
         {
-            BluetoothClient.onDataReceived(0, bytes);
+            if (noneMsgTime > 5)
+            {
+                bluetoothStatusEnum = BluetoothStatusEnum.ConnectFail;
+                EmitOnConnectionFailed();
+                return;
+            }
+            else if (byteMainQueue.Count > 0)
+            {
+                bluetoothStatusEnum = BluetoothStatusEnum.ConnectSuccess;
+                EmitOnConnected();
+            }
+        }
+        else if (bluetoothStatusEnum == BluetoothStatusEnum.ConnectSuccess)
+        {
+            if (noneMsgTime > 5)
+            {
+                bluetoothStatusEnum = BluetoothStatusEnum.ConnectFail;
+                EmitOnConnectionFailed();
+            }
+        }
+        else
+        {
+            byteMainQueue.Clear();
+            return;
+        }
+        if (byteMainQueue.Count == 0)
+        {
+            noneMsgTime += Time.deltaTime;
+            return;
+        }
+        noneMsgTime = 0;
+        while (byteMainQueue.Count > 0)
+        {
+            EmitOnCharacteristicChanged(byteMainQueue.Dequeue());
         }
     }
 
-    void sendMsg()
+    public void SendMsg(string data)
     {
+        Debug.LogWarning("sendMsgToBle: " + data);
         EndPoint point = new IPEndPoint(IPAddress.Parse(localIP), targetPort);
-        client.SendTo(Encoding.UTF8.GetBytes("1"), point);
-        Thread.Sleep(1000);
-        point = new IPEndPoint(IPAddress.Parse(localIP), targetPort);
-        client.SendTo(Encoding.UTF8.GetBytes("3"), point);
-        Thread.Sleep(1000);
+        client.SendTo(Encoding.UTF8.GetBytes(data), point);
     }
 
     void ReciveMsg()
@@ -82,4 +121,57 @@ public class BleUDP : MonoBehaviour
             }
         }
     }
+
+    public void ScanNearbyDevices()
+    {
+        EmitOnScanEnded();
+    }
+
+    public void Connect()
+    {
+        noneMsgTime = 0;
+        bluetoothStatusEnum = BluetoothStatusEnum.Connecting;
+        SendMsg("V");
+    }
+
+    public void Disconnect()
+    {
+        bluetoothStatusEnum = BluetoothStatusEnum.Connect;
+    }
+
+    void EmitOnConnected()
+    {
+        try
+        {
+            OnConnected?.Invoke();
+        }
+        catch (Exception) { }
+    }
+
+    void EmitOnConnectionFailed()
+    {
+        try
+        {
+            OnConnectionFailed?.Invoke();
+        }
+        catch (Exception) { }
+    }
+
+    void EmitOnCharacteristicChanged(byte[] bytes)
+    {
+        try
+        {
+            OnCharacteristicChanged?.Invoke(bytes);
+        }
+        catch (Exception) { }
+    }
+
+    void EmitOnScanEnded()
+    {
+        try
+        {
+            OnScanEnded?.Invoke();
+        }
+        catch (Exception) { }
+    }
 }