ControllerInfo.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using EZXR.Glass.Core;
  5. using EZXR.Glass.Inputs;
  6. using EZXR.Glass.SixDof;
  7. using UnityEngine;
  8. namespace EZXR.Glass.Inputs
  9. {
  10. [ScriptExecutionOrder(-48)]
  11. public class ControllerInfo : InputInfoBase
  12. {
  13. public Transform handleOrigin;
  14. public Transform tipPoint;
  15. /// <summary>
  16. /// 手柄当前是否已配对
  17. /// </summary>
  18. protected bool isBinding = false;
  19. public bool IsBinding
  20. {
  21. get
  22. {
  23. return isBinding;
  24. }
  25. }
  26. /// <summary>
  27. /// 手柄当前是否已连接
  28. /// </summary>
  29. protected bool isConnected = false;
  30. public bool IsConnected
  31. {
  32. get
  33. {
  34. return isConnected;
  35. }
  36. }
  37. /// <summary>
  38. /// 手柄当前电量
  39. /// </summary>
  40. protected float powerStats = 0.0f;
  41. public float PowerStats
  42. {
  43. get
  44. {
  45. return powerStats;
  46. }
  47. }
  48. /// <summary>
  49. /// 手柄当前是否被握持
  50. /// </summary>
  51. protected bool isHeld;
  52. public bool IsHeld
  53. {
  54. get
  55. {
  56. return isHeld;
  57. }
  58. }
  59. /// <summary>
  60. /// 手柄当前是否被静置
  61. /// </summary>
  62. protected bool isSilent;
  63. public bool IsSilent
  64. {
  65. get
  66. {
  67. return isSilent;
  68. }
  69. }
  70. protected Vector2 axis2DCoord;
  71. /// <summary>
  72. /// 监听手柄的生命状态改变(立即发生)
  73. /// </summary>
  74. private bool bindingChanged = false;
  75. private bool connectedChanged = false;
  76. private bool powerChanged = false;
  77. private bool holdChanged = false;
  78. private bool silenceChanged = false;
  79. /// <summary>
  80. /// 监听到生命状态改变的回调(在Update中发生)
  81. /// 可能立即发生也可能滞后一帧
  82. /// </summary>
  83. private Action<bool> bindingAction;
  84. private Action<bool> connectedAction;
  85. private Action<float> powerChangedAction;
  86. private Action<bool> holdChangedAction;
  87. private Action<bool> silenceChangedAction;
  88. /// 保存按键状态(在Update中发生,可能立即发生也可能滞后一帧)
  89. private Dictionary<HandleKeyCode, HandleKeyEvent> buttonState;
  90. /// 监听按键状态的改变(立即发生)
  91. private Dictionary<HandleKeyCode, bool> buttonStateChanged;
  92. //private Dictionary<HandleKeyCode, float> buttonDownTimeSpan;
  93. private bool isPaused = false;
  94. /// <summary>
  95. /// 当前眼镜视野中是否存在这个手
  96. /// </summary>
  97. public override bool Exist
  98. {
  99. get
  100. {
  101. if (Application.isEditor)
  102. {
  103. return true;
  104. }
  105. return isConnected;
  106. }
  107. }
  108. /// <summary>
  109. /// 手掌正在朝向头部
  110. /// </summary>
  111. /// <param name="angle"></param>
  112. /// <returns></returns>
  113. public override bool isPalmFacingHead(float angle = 90) { return false; }
  114. #region 手交互能力开关
  115. /// <summary>
  116. /// 设置或获得当前手的显示状态(仅仅影响显示,并不影响交互)
  117. /// </summary>
  118. private bool visibility = true;
  119. public override bool Visibility
  120. {
  121. get
  122. {
  123. /*if (handType == HandType.Left) return false;
  124. else */return visibility;
  125. }
  126. set
  127. {
  128. // 判断是否开发者自定义了手柄模型
  129. //if (handType == HandType.Right)
  130. {
  131. var dummy = handType == HandType.Left ? "LeftDummy" : "RightDummy";
  132. // 若在handleOrigin下添加自定义的手柄模型,则隐藏默认手柄
  133. var hasAlter = handleOrigin.GetComponentsInChildren<Renderer>().Length > 0;
  134. if (!hasAlter) transform.Find(dummy).gameObject.SetActive(value);
  135. else handleOrigin.gameObject.SetActive(value);
  136. visibility = value;
  137. }
  138. }
  139. }
  140. /// <summary>
  141. /// 设置或获得远距离射线交互状态
  142. /// </summary>
  143. public override bool RaycastInteraction
  144. {
  145. get
  146. {
  147. return GetComponent<InputRaycast>().enabled;
  148. }
  149. set
  150. {
  151. GetComponent<InputRaycast>().enabled = value;
  152. }
  153. }
  154. /// <summary>
  155. /// 设置或获得近距离交互状态
  156. /// </summary>
  157. public override bool TouchInteraction
  158. {
  159. get
  160. {
  161. return false;
  162. }
  163. set
  164. {
  165. }
  166. }
  167. /// <summary>
  168. /// 设置或获得手部的物理碰撞交互状态
  169. /// </summary>
  170. public override bool PhysicsInteraction
  171. {
  172. get
  173. {
  174. return false;
  175. }
  176. set
  177. {
  178. }
  179. }
  180. #endregion
  181. protected override void Awake()
  182. {
  183. base.Awake();
  184. buttonState = new Dictionary<HandleKeyCode, HandleKeyEvent>();
  185. //buttonDownTimeSpan = new Dictionary<HandleKeyCode, float>();
  186. buttonStateChanged = new Dictionary<HandleKeyCode, bool>();
  187. }
  188. protected override void Update()
  189. {
  190. base.Update();
  191. UpdateStatus();
  192. if (handleOrigin != null)
  193. {
  194. //射线方向
  195. if (!(HandleControllerManager.SetRayDirByExternal != null && HandleControllerManager.SetRayDirByExternal(this, ref rayDirection)))
  196. {
  197. rayDirection = handleOrigin.forward;
  198. }
  199. //射线起点
  200. if (!(HandleControllerManager.SetRayStartPointByExternal != null && HandleControllerManager.SetRayStartPointByExternal(this, ref rayPoint_Start)))
  201. {
  202. rayPoint_Start = handleOrigin.position + rayDirection * rayStartDistance;
  203. }
  204. }
  205. }
  206. private void OnApplicationPause(bool pause)
  207. {
  208. //Debug.Log($"HandleControllerInfo, OnApplicationPause: pause = {pause} handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats} ({Time.frameCount})");
  209. if (!pause)
  210. {
  211. isBinding = HandleControllerManager.Instance.GetBindState(handType);
  212. isConnected = HandleControllerManager.Instance.GetConnectState(handType);
  213. powerStats = HandleControllerManager.Instance.GetPowerStats(handType);
  214. Debug.Log($"HandleControllerInfo, OnApplicationPause: pause = {pause} handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats}");
  215. }
  216. isPaused = pause;
  217. //UpdatePinching();
  218. buttonState.Clear(); buttonStateChanged.Clear();
  219. startPinch = false; endPinch = false; isPinching = false;
  220. }
  221. private void OnEnable()
  222. {
  223. //Debug.Log($"HandleControllerInfo, OnEnable: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats} ({Time.frameCount})");
  224. isBinding = HandleControllerManager.Instance.GetBindState(handType);
  225. isConnected = HandleControllerManager.Instance.GetConnectState(handType);
  226. powerStats = HandleControllerManager.Instance.GetPowerStats(handType);
  227. Debug.Log($"HandleControllerInfo, OnEnable: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats}");
  228. //UpdatePinching();
  229. buttonState.Clear(); buttonStateChanged.Clear();
  230. startPinch = false; endPinch = false; isPinching = false;
  231. }
  232. private void OnDisable()
  233. {
  234. //UpdatePinching();
  235. buttonState.Clear(); buttonStateChanged.Clear();
  236. startPinch = false; endPinch = false; isPinching = false;
  237. Debug.Log($"HandleControllerInfo, OnDisable: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats} ({Time.frameCount})");
  238. }
  239. public override void Init(HandType handType)
  240. {
  241. base.Init(handType);
  242. //if (handType == HandType.Right)
  243. {
  244. // 若在handleOrigin下添加自定义的手柄模型,则隐藏默认手柄
  245. var hasAlter = handleOrigin.GetComponentsInChildren<Renderer>().Length > 0;
  246. // fix: 控制器切换时不能任意设置手柄显示
  247. if (hasAlter) transform.Find(handType == HandType.Left ? "LeftDummy" : "RightDummy").gameObject.SetActive(!hasAlter);
  248. }
  249. isBinding = HandleControllerManager.Instance.GetBindState(handType);
  250. isConnected = HandleControllerManager.Instance.GetConnectState(handType);
  251. powerStats = HandleControllerManager.Instance.GetPowerStats(handType);
  252. Debug.Log($"HandleControllerInfo, Init: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats}");
  253. StartCoroutine(CheckStatus());
  254. }
  255. public void UpdateBindingState(bool status, Action<bool> callback)
  256. {
  257. if (isBinding == status) return;
  258. isBinding = status;
  259. bindingChanged = true;
  260. bindingAction = callback;
  261. Debug.Log($"HandleControllerInfo, UpdateBinding: handType = {this.handType} isBinding = {status}");
  262. if (isPaused || !gameObject.activeInHierarchy) UpdateStatus();
  263. }
  264. public void UpdateConnectedState(bool connected, Action<bool> callback)
  265. {
  266. if (isConnected == connected) return;
  267. isConnected = connected;
  268. connectedChanged = true;
  269. connectedAction = callback;
  270. Debug.Log($"HandleControllerInfo, UpdateConnectedState: handType = {this.handType} isConnected = {connected}");
  271. if (!connected) { buttonState.Clear(); buttonStateChanged.Clear(); }
  272. if (!connected) { startPinch = false; endPinch = false; isPinching = false; }
  273. if (isPaused || !gameObject.activeInHierarchy) UpdateStatus();
  274. }
  275. public void UpdatePowerStats(float power, Action<float> callback)
  276. {
  277. Debug.Log($"HandleControllerInfo, UpdatePowerStats: handType = {this.handType} power = {power}");
  278. if (powerStats == power) return;
  279. powerStats = power;
  280. powerChanged = true;
  281. powerChangedAction = callback;
  282. if (isPaused || !gameObject.activeInHierarchy) UpdateStatus();
  283. }
  284. public void UpdateButtonState(HandleKeyCode keyCode, bool pressed)
  285. {
  286. if (isPaused || !gameObject.activeInHierarchy) return;
  287. //Debug.Log($"HandleControllerInfo, {handType} {keyCode} StateChanged to {(pressed ? "pressed" : "released")} ({Time.frameCount})");
  288. if (!buttonState.ContainsKey(keyCode))
  289. {
  290. buttonState[keyCode] = pressed ? HandleKeyEvent.Idle : HandleKeyEvent.Pressing;
  291. buttonStateChanged[keyCode] = true;
  292. }
  293. else if ((pressed && buttonState[keyCode] == HandleKeyEvent.Idle) || (!pressed && buttonState[keyCode] == HandleKeyEvent.Pressing))
  294. {
  295. buttonStateChanged[keyCode] = true;
  296. }
  297. }
  298. public void UpdateAxis2D(Vector2 coord)
  299. {
  300. if (isPaused || !gameObject.activeInHierarchy) return;
  301. axis2DCoord = coord;
  302. }
  303. public void UpdateHoldState(bool isHeld, Action<bool> callback)
  304. {
  305. if (this.isHeld == isHeld) return;
  306. this.isHeld = isHeld;
  307. holdChanged = true;
  308. holdChangedAction = callback;
  309. //Debug.Log($"HandleControllerInfo, UpdateHoldState: handType = {this.handType} isHeld = {isHeld} ({Time.frameCount})");
  310. if (isPaused || !gameObject.activeInHierarchy) UpdateStatus();
  311. }
  312. public void UpdateSilenceState(bool isSilent, Action<bool> callback)
  313. {
  314. if (this.isSilent == isSilent) return;
  315. this.isSilent = isSilent;
  316. silenceChanged = true;
  317. silenceChangedAction = callback;
  318. //Debug.Log($"HandleControllerInfo, UpdateSilenceState: handType = {this.handType} isSilent = {isSilent} ({Time.frameCount})");
  319. if (isPaused || !gameObject.activeInHierarchy) UpdateStatus();
  320. }
  321. public bool GetButtonDown(HandleKeyCode keyCode)
  322. {
  323. if (!isPaused && isConnected && buttonState.ContainsKey(keyCode))
  324. return buttonState[keyCode] == HandleKeyEvent.Down;
  325. return false;
  326. }
  327. public bool GetButtonUp(HandleKeyCode keyCode)
  328. {
  329. if (!isPaused && isConnected && buttonState.ContainsKey(keyCode))
  330. return buttonState[keyCode] == HandleKeyEvent.Up;
  331. return false;
  332. }
  333. public bool GetButton(HandleKeyCode keyCode)
  334. {
  335. if (!isPaused && isConnected && buttonState.ContainsKey(keyCode))
  336. return buttonState[keyCode] == HandleKeyEvent.Pressing;
  337. return false;
  338. }
  339. public Vector2 GetAxis2D()
  340. {
  341. return axis2DCoord;
  342. }
  343. protected override void UpdatePinching()
  344. {
  345. var keys = new List<HandleKeyCode>(buttonStateChanged.Keys);
  346. for (int j = 0; j < keys.Count; ++j)
  347. {
  348. var keyCode = keys[j];
  349. if (!buttonStateChanged[keyCode]) continue;
  350. if (buttonState[keyCode] == HandleKeyEvent.Idle)
  351. {
  352. buttonState[keyCode] = HandleKeyEvent.Down;
  353. //Debug.Log($"HandleControllerInfo, {handType} {keyCode} change to Down from Idle ({Time.frameCount})");
  354. //按下扳机键触发开始捏合动作
  355. if (keyCode == HandleKeyCode.Trigger) startPinch = true;
  356. }
  357. else if (buttonState[keyCode] == HandleKeyEvent.Pressing)
  358. {
  359. buttonState[keyCode] = HandleKeyEvent.Up;
  360. //Debug.Log($"HandleControllerInfo, {handType} {keyCode} change to Up from Pressing ({Time.frameCount})");
  361. //松开扳机键触发结束捏合动作
  362. if (keyCode == HandleKeyCode.Trigger) endPinch = true;
  363. }
  364. //buttonStateChanged.Remove(keyCode);
  365. }
  366. keys = new List<HandleKeyCode>(buttonState.Keys);
  367. for (int i = 0; i < keys.Count; ++i)
  368. {
  369. var keyCode = keys[i];
  370. if (buttonStateChanged.ContainsKey(keyCode))
  371. {
  372. buttonStateChanged.Remove(keyCode);
  373. continue;
  374. }
  375. if (buttonState[keyCode] == HandleKeyEvent.Down)
  376. {
  377. buttonState[keyCode] = HandleKeyEvent.Pressing;
  378. //Debug.Log($"HandleControllerInfo, {handType} {keyCode} change to Pressing from Down ({Time.frameCount})");
  379. // startPinch结束,触发持续捏合
  380. if (keyCode == HandleKeyCode.Trigger) { startPinch = false; isPinching = true; }
  381. }
  382. else if (buttonState[keyCode] == HandleKeyEvent.Up)
  383. {
  384. buttonState[keyCode] = HandleKeyEvent.Idle;
  385. //Debug.Log($"HandleControllerInfo, {handType} {keyCode} change to Idle from Up ({Time.frameCount})");
  386. // endPinch结束,触发结束捏合
  387. if (keyCode == HandleKeyCode.Trigger) { endPinch = false; isPinching = false; }
  388. }
  389. }
  390. }
  391. private void UpdateStatus()
  392. {
  393. if (bindingChanged)
  394. {
  395. if (bindingAction != null) bindingAction(isBinding);
  396. bindingChanged = false;
  397. }
  398. if (connectedChanged)
  399. {
  400. if (connectedAction != null) connectedAction(isConnected);
  401. connectedChanged = false;
  402. Visibility = isConnected;
  403. RaycastInteraction = isConnected;
  404. TouchInteraction = isConnected;
  405. PhysicsInteraction = isConnected;
  406. }
  407. if (powerChanged)
  408. {
  409. if (powerChangedAction != null) powerChangedAction(powerStats);
  410. powerChanged = false;
  411. }
  412. if (holdChanged)
  413. {
  414. if (holdChangedAction != null) holdChangedAction(isHeld);
  415. holdChanged = false;
  416. }
  417. if (silenceChanged)
  418. {
  419. if (silenceChangedAction != null) silenceChangedAction(isSilent);
  420. silenceChanged = false;
  421. }
  422. }
  423. // for fix
  424. public IEnumerator CheckStatus()
  425. {
  426. yield return new WaitUntil(() => SessionManager.Instance != null && SessionManager.Instance.IsInited);
  427. isBinding = HandleControllerManager.Instance.GetBindState(handType);
  428. isConnected = HandleControllerManager.Instance.GetConnectState(handType);
  429. powerStats = HandleControllerManager.Instance.GetPowerStats(handType);
  430. Debug.Log($"HandleControllerInfo, Check: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats} ({Time.frameCount})");
  431. Visibility = isConnected;
  432. RaycastInteraction = isConnected;
  433. TouchInteraction = isConnected;
  434. PhysicsInteraction = isConnected;
  435. }
  436. }
  437. }