DeviceView_ItemShow.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. using AppUI.Bluetooth;
  2. using AppUI.Localization;
  3. using AppUI.Manager;
  4. using AppUI.Manager.View;
  5. using AppUI.View.Home.Main;
  6. using InfraredManager;
  7. using SmartBowSDK;
  8. using System;
  9. using TMPro;
  10. using UnityEngine;
  11. using UnityEngine.UI;
  12. using BLEAimhandler = AppUI.Bluetooth.AimHandler;
  13. using SdkAimDeviceInfo = SmartBowSDK.AimDeviceInfo;
  14. namespace AppUI.View.Home.DeviceView
  15. {
  16. public class DeviceView_ItemShow : MonoBehaviour
  17. {
  18. [Tooltip("当前选择的用户设备")]
  19. [SerializeField] BluetoothPlayer bluetoothPlayer = BluetoothPlayer.FIRST_PLAYER;
  20. [SerializeField] Image selectPanel;
  21. [SerializeField] Button btnBg;
  22. [SerializeField] TMP_Text titleText;
  23. [Header("操作按钮(连接/屏幕定位 + 切换设备)")]
  24. [SerializeField] Button btnPrimaryAction;
  25. [SerializeField] Image btnPrimaryActionBg;
  26. [SerializeField] TMP_Text btnPrimaryActionLabel;
  27. [SerializeField] Button btnSwitchDevice;
  28. [SerializeField] Image btnSwitchDeviceBg;
  29. [SerializeField] TMP_Text btnSwitchDeviceLabel;
  30. [SerializeField] GameObject bettery;
  31. [SerializeField] GameObject betteryBar;
  32. [SerializeField] GameObject betteryValue;
  33. [SerializeField] Image bowBg;
  34. float countingTime1 = 5;
  35. [SerializeField] int deviceIndex;
  36. bool bShowInfo;
  37. string omitText;
  38. int dotCount;
  39. float interval = 0.5f;
  40. float timer;
  41. [SerializeField] TMP_Text curConnectStatus;
  42. [SerializeField] TMP_Text curScreenPositioningStatus;
  43. const string KeyScreenPositioningDone = "appui-sideslip-screen-positioning-done";
  44. const string KeyScreenPositioningIncomplete = "appui-sideslip-screen-positioning-incomplete";
  45. const string KeyStatusNotConnected = "appui-device-status-not-connected";
  46. const string KeyStatusConnecting = "appui-device-status-connecting";
  47. const string KeyStatusConnected = "appui-device-status-connected";
  48. const string KeyBtnConnect = "appui-device-btn-connect";
  49. const string KeyBtnDisconnect = "appui-device-btn-disconnect";
  50. const string KeyBtnSwitch = "appui-device-btn-switch";
  51. const string KeyBtnScreenPositioning = "appui-device-btn-screen-positioning";
  52. const string KeyTipInfraredConnect = "appui-device-tip-infrared-connect";
  53. static readonly Color32 BlackBg = new Color32(0, 0, 0, 255);
  54. static readonly Color32 WhiteBg = new Color32(255, 255, 255, 255);
  55. static readonly Color32 WhiteText = new Color32(255, 255, 255, 255);
  56. static readonly Color32 BlackText = new Color32(50, 50, 50, 255);
  57. static readonly Color32 StatusCompleteColor = new Color32(0, 0, 0, 255);
  58. static readonly Color32 StatusIncompleteColor = new Color32(145, 144, 144, 255);
  59. SmartBowDeviceHub Hub => SmartBowDeviceHub.ins;
  60. public BluetoothPlayer Player => bluetoothPlayer;
  61. /// <summary>连接 / 屏幕定位按钮节点。</summary>
  62. public Button BtnPrimaryAction => btnPrimaryAction;
  63. /// <summary>切换设备按钮节点。</summary>
  64. public Button BtnSwitchDevice => btnSwitchDevice;
  65. public GameObject BtnPrimaryActionNode => btnPrimaryAction != null ? btnPrimaryAction.gameObject : null;
  66. public GameObject BtnSwitchDeviceNode => btnSwitchDevice != null ? btnSwitchDevice.gameObject : null;
  67. enum PrimaryActionKind
  68. {
  69. ConnectSideSlip,
  70. InfraredView,
  71. Disconnect,
  72. }
  73. PrimaryActionKind _primaryActionKind = PrimaryActionKind.ConnectSideSlip;
  74. bool IsConnectSuccess()
  75. {
  76. return Hub != null && Hub.IsConnected(bluetoothPlayer);
  77. }
  78. bool IsConnecting()
  79. {
  80. return Hub != null && Hub.IsConnecting(bluetoothPlayer);
  81. }
  82. bool IsScreenPositioned()
  83. {
  84. InfraredCameraHelper helper = InfraredCameraHelper.GetInstance();
  85. return helper != null && helper.IsScreenLoateOK();
  86. }
  87. void Awake()
  88. {
  89. ResolveUiReferences();
  90. if (Hub?.Aim != null)
  91. Hub.Aim.aimDeviceInfoChangeEvent += onShowDeviceInfo;
  92. }
  93. void ResolveUiReferences()
  94. {
  95. if (titleText == null)
  96. {
  97. Transform title = transform.Find("Panel/title");
  98. if (title != null)
  99. titleText = title.GetComponent<TMP_Text>();
  100. }
  101. ResolveActionButtonReferences();
  102. }
  103. void ResolveActionButtonReferences()
  104. {
  105. if (btnPrimaryAction == null)
  106. {
  107. Transform screen = transform.Find("connected/bottom/Buttons/Screen");
  108. if (screen != null)
  109. {
  110. btnPrimaryAction = screen.GetComponent<Button>();
  111. btnPrimaryActionBg = screen.GetComponent<Image>();
  112. btnPrimaryActionLabel = screen.GetComponentInChildren<TMP_Text>(true);
  113. }
  114. }
  115. if (btnSwitchDevice == null)
  116. {
  117. Transform switchBtn = transform.Find("connected/bottom/Buttons/Switch");
  118. if (switchBtn != null)
  119. {
  120. btnSwitchDevice = switchBtn.GetComponent<Button>();
  121. btnSwitchDeviceBg = switchBtn.GetComponent<Image>();
  122. btnSwitchDeviceLabel = switchBtn.GetComponentInChildren<TMP_Text>(true);
  123. }
  124. }
  125. }
  126. void SetDeviceTitle(string text)
  127. {
  128. if (titleText != null)
  129. titleText.text = text;
  130. }
  131. void SetDeviceSprite(Sprite sprite)
  132. {
  133. if (bowBg != null && sprite != null)
  134. bowBg.sprite = sprite;
  135. }
  136. void OnEnable()
  137. {
  138. AppUILocalization.OnLanguageChanged += HandleLanguageChanged;
  139. }
  140. void OnDisable()
  141. {
  142. AppUILocalization.OnLanguageChanged -= HandleLanguageChanged;
  143. }
  144. void HandleLanguageChanged(LanguageEnum _)
  145. {
  146. onUpdateStatusInfo();
  147. RefreshActionButtons();
  148. }
  149. void Start()
  150. {
  151. ResolveUiReferences();
  152. btnBg?.onClick.AddListener(OnSelectEvent);
  153. btnPrimaryAction?.onClick.AddListener(OnClickPrimaryAction);
  154. btnSwitchDevice?.onClick.AddListener(OnClickSwitchDevice);
  155. if (Hub != null)
  156. {
  157. Hub.OnStateChanged += OnHubStateChanged;
  158. if (IsConnectSuccess())
  159. {
  160. int battery = Hub.GetBattery(bluetoothPlayer);
  161. if (battery > 0)
  162. RenderBattery(-1, battery);
  163. }
  164. }
  165. onUpdateStatusInfo();
  166. RefreshActionButtons();
  167. //开始选择一次
  168. if(bluetoothPlayer == BluetoothPlayer.FIRST_PLAYER)
  169. {
  170. OnSelectEvent();
  171. }
  172. }
  173. void OnDestroy()
  174. {
  175. if (Hub != null)
  176. Hub.OnStateChanged -= OnHubStateChanged;
  177. if (Hub?.Aim != null)
  178. Hub.Aim.aimDeviceInfoChangeEvent -= onShowDeviceInfo;
  179. }
  180. void OnHubStateChanged(SmartBowDeviceState state)
  181. {
  182. onUpdateStatusInfo();
  183. RefreshActionButtons();
  184. }
  185. void Update()
  186. {
  187. if (Hub == null) return;
  188. if (IsConnectSuccess())
  189. {
  190. if (countingTime1 < 5)
  191. countingTime1 += Time.deltaTime;
  192. else
  193. {
  194. countingTime1 = 0;
  195. RenderBattery(-1, Hub.GetBattery(bluetoothPlayer));
  196. }
  197. }
  198. else if (!IsConnecting())
  199. {
  200. onShowDeviceInfo();
  201. RenderBattery(-1, 0);
  202. }
  203. else
  204. {
  205. RenderBattery(-1, 0);
  206. onShowDeviceInfo();
  207. }
  208. onUpdateStatusInfo();
  209. }
  210. void UpdateLoadingText()
  211. {
  212. timer += Time.deltaTime;
  213. if (timer >= interval)
  214. {
  215. dotCount = (dotCount + 1) % 4;
  216. omitText = new string('.', dotCount);
  217. timer = 0f;
  218. }
  219. }
  220. public void StopLoading()
  221. {
  222. dotCount = 0;
  223. omitText = "";
  224. }
  225. public void RenderBattery(int deviceID, int value)
  226. {
  227. if (betteryBar == null || betteryValue == null) return;
  228. Image img = betteryBar.GetComponent<Image>();
  229. Text txt = betteryValue.GetComponent<Text>();
  230. if (img == null || txt == null) return;
  231. img.fillAmount = value / 100f;
  232. txt.text = value + "%";
  233. }
  234. bool TryGetDeviceInfo(out int type, out bool bInitMac)
  235. {
  236. type = -1;
  237. bInitMac = false;
  238. var aim = Hub?.Aim;
  239. if (aim == null) return false;
  240. var player = (BluetoothPlayer)deviceIndex;
  241. SdkAimDeviceInfo info = aim.GetAimDeviceInfo(player);
  242. if (info == null) return false;
  243. type = aim.GetDeviceType(player);
  244. bInitMac = info.bInitMac;
  245. return true;
  246. }
  247. public void onShowDeviceInfo()
  248. {
  249. if (!TryGetDeviceInfo(out int deviceType, out bool bInitMac) || deviceType == -1 || !bInitMac)
  250. {
  251. bShowInfo = false;
  252. RefreshActionButtons();
  253. return;
  254. }
  255. bShowInfo = true;
  256. var deviceTypeEnum = (AimDeviceType)deviceType;
  257. if (Hub == null || !Hub.TryGetDeviceDisplay(deviceTypeEnum, out Sprite sprite, out string displayName))
  258. {
  259. bShowInfo = false;
  260. RefreshActionButtons();
  261. return;
  262. }
  263. SetDeviceTitle(displayName);
  264. SetDeviceSprite(sprite);
  265. RefreshActionButtons();
  266. }
  267. public void onUpdateStatusInfo()
  268. {
  269. if (Hub == null || curConnectStatus == null) return;
  270. if (IsConnecting())
  271. UpdateLoadingText();
  272. else
  273. StopLoading();
  274. string statusKey = ResolveStatusTextKey(Hub.GetStatusTextKey(bluetoothPlayer));
  275. curConnectStatus.text = AppUILocalization.GetTextByKey(statusKey, curConnectStatus) + omitText;
  276. curConnectStatus.color = IsConnectSuccess() ? StatusCompleteColor : StatusIncompleteColor;
  277. RefreshScreenPositioningStatusText();
  278. }
  279. void RefreshScreenPositioningStatusText()
  280. {
  281. if (curScreenPositioningStatus == null) return;
  282. if (!bInfraredDevices())
  283. {
  284. curScreenPositioningStatus.gameObject.SetActive(false);
  285. return;
  286. }
  287. curScreenPositioningStatus.gameObject.SetActive(true);
  288. bool positioned = IsScreenPositioned();
  289. curScreenPositioningStatus.text = AppUILocalization.GetTextByKey(positioned ? KeyScreenPositioningDone : KeyScreenPositioningIncomplete, curScreenPositioningStatus);
  290. curScreenPositioningStatus.color = positioned ? StatusCompleteColor : StatusIncompleteColor;
  291. }
  292. /// <summary>刷新主操作按钮与切换按钮的文案、样式与可见性。</summary>
  293. public void RefreshActionButtons()
  294. {
  295. ResolveActionButtonReferences();
  296. RefreshSwitchButton();
  297. RefreshPrimaryActionButton();
  298. RefreshScreenPositioningStatusText();
  299. }
  300. void RefreshSwitchButton()
  301. {
  302. if (btnSwitchDevice == null) return;
  303. bool show = bShowInfo;
  304. if (btnSwitchDevice.gameObject.activeSelf != show)
  305. btnSwitchDevice.gameObject.SetActive(show);
  306. if (!show) return;
  307. ApplyButtonStyle(btnSwitchDeviceBg, btnSwitchDeviceLabel, false, KeyBtnSwitch);
  308. }
  309. void RefreshPrimaryActionButton()
  310. {
  311. if (btnPrimaryAction == null) return;
  312. bool connected = IsConnectSuccess();
  313. bool screenPositioned = IsScreenPositioned();
  314. bool isInfrared = bInfraredDevices();
  315. bool isNineAxis = bNineAxisDevices();
  316. if (!bShowInfo)
  317. {
  318. btnPrimaryAction.gameObject.SetActive(false);
  319. return;
  320. }
  321. btnPrimaryAction.gameObject.SetActive(true);
  322. if (isInfrared)
  323. {
  324. if (connected)
  325. {
  326. _primaryActionKind = PrimaryActionKind.InfraredView;
  327. ApplyButtonStyle(
  328. btnPrimaryActionBg,
  329. btnPrimaryActionLabel,
  330. !screenPositioned,
  331. KeyBtnScreenPositioning);
  332. }
  333. else
  334. {
  335. _primaryActionKind = PrimaryActionKind.ConnectSideSlip;
  336. ApplyButtonStyle(btnPrimaryActionBg, btnPrimaryActionLabel, true, KeyBtnConnect);
  337. }
  338. return;
  339. }
  340. if (isNineAxis && connected)
  341. {
  342. _primaryActionKind = PrimaryActionKind.Disconnect;
  343. ApplyButtonStyle(btnPrimaryActionBg, btnPrimaryActionLabel, false, KeyBtnDisconnect);
  344. return;
  345. }
  346. _primaryActionKind = PrimaryActionKind.ConnectSideSlip;
  347. ApplyButtonStyle(btnPrimaryActionBg, btnPrimaryActionLabel, true, KeyBtnConnect);
  348. }
  349. static string ResolveStatusTextKey(string legacyKey)
  350. {
  351. return legacyKey switch
  352. {
  353. "Connect_BLE_NotConnected" => KeyStatusNotConnected,
  354. "Connect_BLE_Connecting" => KeyStatusConnecting,
  355. "Connect_BLE_Connected" => KeyStatusConnected,
  356. _ => legacyKey
  357. };
  358. }
  359. static void ApplyButtonStyle(Image bg, TMP_Text label, bool blackBackground, string textKey)
  360. {
  361. if (bg != null)
  362. bg.color = blackBackground ? BlackBg : WhiteBg;
  363. if (label != null)
  364. {
  365. label.text = AppUILocalization.GetTextByKey(textKey);
  366. label.color = blackBackground ? WhiteText : BlackText;
  367. }
  368. }
  369. void OnClickPrimaryAction()
  370. {
  371. AudioMgr.ins.PlayBtn();
  372. if (!getPanelStatus()) return;
  373. Hub?.SetActivePlayer(bluetoothPlayer);
  374. Hub?.Aim?.SetAimDeviceSelectIndex(deviceIndex);
  375. if (_primaryActionKind == PrimaryActionKind.InfraredView)
  376. {
  377. if (!IsConnectSuccess())
  378. {
  379. PopupMgr.ins.ShowTipTop(AppUILocalization.GetTextByKey(KeyTipInfraredConnect));
  380. return;
  381. }
  382. ViewManager.ShowView(UIViewType.InfraredView);
  383. return;
  384. }
  385. if (_primaryActionKind == PrimaryActionKind.Disconnect)
  386. {
  387. OnDisConnectedEvent();
  388. return;
  389. }
  390. Hub?.Aim?.PrepareDirectSideSlipConnect(deviceIndex);
  391. ModuleViewMgr.ins.ShowSideSlip(guideDeviceType: ResolveGuideDeviceTypeForSideSlip());
  392. }
  393. AimDeviceType? ResolveGuideDeviceTypeForSideSlip()
  394. {
  395. BLEAimhandler aim = Hub?.Aim;
  396. if (aim == null)
  397. return null;
  398. int deviceType = aim.GetDeviceType(bluetoothPlayer);
  399. if (deviceType == (int)AimDeviceType.NONE)
  400. return null;
  401. return (AimDeviceType)deviceType;
  402. }
  403. void OnClickSwitchDevice()
  404. {
  405. AudioMgr.ins.PlayBtn();
  406. if (!getPanelStatus()) return;
  407. Hub?.SetActivePlayer(bluetoothPlayer);
  408. Hub?.Aim?.SetAimDeviceSelectIndex(deviceIndex);
  409. if (IsConnectSuccess())
  410. OnDisConnectedEvent();
  411. Hub?.CancelConnecting();
  412. Hub?.Aim?.onCreateTempAimDeviceInfo();
  413. DeviceView deviceView = GetComponentInParent<DeviceView>();
  414. if (deviceView != null)
  415. {
  416. deviceView.BeginDeviceSelectionFlow();
  417. return;
  418. }
  419. if (GlobalData.MyDeviceMode == DeviceMode.Gun)
  420. ViewManager.ShowView(UIViewType.DeviceGunView);
  421. else
  422. ViewManager.ShowView(UIViewType.DeviceArcheryView);
  423. }
  424. void CloseAllPanelStatus()
  425. {
  426. DeviceView root = GetComponentInParent<DeviceView>();
  427. if (root == null) return;
  428. foreach (DeviceView_ItemShow item in root.GetComponentsInChildren<DeviceView_ItemShow>(true))
  429. {
  430. if (item.selectPanel != null)
  431. item.selectPanel.enabled = false;
  432. }
  433. }
  434. public void setPanelStatus(bool active)
  435. {
  436. if (selectPanel != null)
  437. selectPanel.enabled = active;
  438. if (!active) return;
  439. Hub?.SetActivePlayer(bluetoothPlayer);
  440. Hub?.Aim?.SetAimDeviceSelectIndex(deviceIndex);
  441. Debug.Log("当前选择的操作蓝牙用户 deviceSelectIndex:" + deviceIndex);
  442. }
  443. public bool getPanelStatus()
  444. {
  445. bool enable = selectPanel != null && selectPanel.enabled;
  446. CloseAllPanelStatus();
  447. setPanelStatus(true);
  448. return enable;
  449. }
  450. public bool getCurrentPanelEnable() => selectPanel != null && selectPanel.enabled;
  451. public bool getBLEConnectState() => IsConnectSuccess();
  452. public void OnConnectedEvent()
  453. {
  454. if (!getPanelStatus()) return;
  455. Hub?.Aim?.SetAimDeviceSelectIndex(deviceIndex);
  456. Hub?.Aim?.onCreateAimDeviceInfoById();
  457. if (IsConnectSuccess())
  458. {
  459. Hub?.ConnectActivePlayer();
  460. return;
  461. }
  462. if (bluetoothPlayer == BluetoothPlayer.FIRST_PLAYER)
  463. Hub?.Connect1P();
  464. else
  465. Hub?.Connect2P();
  466. }
  467. public void OnDisConnectedEvent()
  468. {
  469. if (!getPanelStatus()) return;
  470. Hub?.Aim?.SetAimDeviceSelectIndex(deviceIndex);
  471. Hub?.Aim?.onCreateAimDeviceInfoById();
  472. if (bluetoothPlayer == BluetoothPlayer.FIRST_PLAYER)
  473. {
  474. if (Hub == null) return;
  475. if (IsConnectSuccess())
  476. Hub.Connect1P();
  477. else
  478. Hub.SetConnectCanceled(true);
  479. }
  480. else if (IsConnectSuccess())
  481. {
  482. Hub?.Set2PNoNeedToReconnect(false);
  483. Hub?.Connect2P();
  484. }
  485. }
  486. public void OnSelectEvent()
  487. {
  488. if (getCurrentPanelEnable()) return;
  489. AudioMgr.ins.PlayBtn();
  490. Hub?.Aim?.SetAimDeviceSelectIndex(deviceIndex);
  491. CloseAllPanelStatus();
  492. setPanelStatus(true);
  493. }
  494. public bool getCurrentItemVisible() => selectPanel.enabled && bShowInfo;
  495. public bool bInfraredDevices()
  496. {
  497. if (!TryGetDeviceInfo(out int deviceType, out bool bInitMac) || deviceType == -1 || !bInitMac)
  498. return false;
  499. switch ((AimDeviceType)deviceType)
  500. {
  501. case AimDeviceType.HOUYIPRO:
  502. case AimDeviceType.Gun:
  503. case AimDeviceType.ARTEMISPRO:
  504. case AimDeviceType.PistolM17:
  505. case AimDeviceType.RifleM416:
  506. return true;
  507. default:
  508. return false;
  509. }
  510. }
  511. public bool bNineAxisDevices()
  512. {
  513. if (!TryGetDeviceInfo(out int deviceType, out bool bInitMac) || deviceType == -1 || !bInitMac)
  514. return false;
  515. return deviceType == (int)AimDeviceType.HOUYI
  516. || deviceType == (int)AimDeviceType.HOUYI2
  517. || deviceType == (int)AimDeviceType.ARTEMIS;
  518. }
  519. }
  520. }