SCInputModule.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using NRKernal;
  7. using UnityEngine;
  8. using UnityEngine.EventSystems;
  9. using UnityEngine.UI;
  10. namespace SC.XR.Unity.Module_InputSystem {
  11. public class SCInputModule : StandaloneInputModule {
  12. public static SCInputModule Instance { get; private set; }
  13. private bool canProcessEvent = true;
  14. private bool canDrag = true;
  15. public static bool IsRayCastResultsSortByDistance = false;
  16. public bool CanProcessEvent { get => canProcessEvent; set => canProcessEvent = value; }
  17. public bool CanDrag { get => canDrag; set => canDrag = value; }
  18. private Camera mRayCasterCamera;
  19. public Camera RayCasterCamera {
  20. get {
  21. if(mRayCasterCamera == null) {
  22. mRayCasterCamera = EnsureUIEventCamera();
  23. }
  24. return mRayCasterCamera;
  25. }
  26. }
  27. private PhysicsRaycaster mPhysicsRaycaster;
  28. public PhysicsRaycaster PhysicsRaycaster {
  29. get {
  30. if(mPhysicsRaycaster == null) {
  31. mPhysicsRaycaster = EnsurePhysicsRaycaster();
  32. }
  33. return mPhysicsRaycaster;
  34. }
  35. }
  36. public LayerMask layerMask;
  37. public float maxDetectDistance=0;
  38. Vector3? lastMousePoint3d;
  39. Vector2 newPos, lastPosition;
  40. Vector3 viewportPos = new Vector3(0.5f, 0.5f, 1.0f);
  41. protected override void Start() {
  42. base.Start();
  43. if(Instance) {
  44. DestroyImmediate(this);
  45. return;
  46. }
  47. DontDestroyOnLoad(gameObject);
  48. Instance = this;
  49. }
  50. public override void Process() {
  51. }
  52. public virtual void ProcessCS(SCPointEventData scPointEventData, Transform posture, int layerMask = 1 << 8, float maxDetectDistance = 30,bool isSimlate=false, RaycastResult simlateResult=new RaycastResult()) {
  53. //if(!eventSystem.isFocused)
  54. // return;
  55. bool usedEvent = SendUpdateEventToSelectedObject();
  56. ProcessSCEventInit(scPointEventData, posture, layerMask, maxDetectDistance);
  57. ProcessSCEvent(scPointEventData, isSimlate, simlateResult);
  58. if(eventSystem.sendNavigationEvents) {
  59. if(!usedEvent)
  60. usedEvent |= SendMoveEventToSelectedObject();
  61. if(!usedEvent)
  62. SendSubmitEventToSelectedObject();
  63. }
  64. }
  65. void ProcessSCEventInit(SCPointEventData scPointEventData, Transform posture, int layerMask, float maxDetectDistance) {
  66. if(this.layerMask.value != 0) {
  67. layerMask = this.layerMask;
  68. }
  69. if(this.maxDetectDistance > 0) {
  70. maxDetectDistance = this.maxDetectDistance;
  71. }
  72. PhysicsRaycaster.eventMask = layerMask;
  73. RayCasterCamera.cullingMask = layerMask;
  74. RayCasterCamera.farClipPlane = maxDetectDistance;
  75. RayCasterCamera.transform.position = posture.position; // posture.position;// Vector3.Lerp(RayCasterCamera.transform.position, targetDetectBase.transform.position,0.3f); //targetDetectBase.transform.position;
  76. RayCasterCamera.transform.rotation = posture.rotation;
  77. List<ICanvasRaycastTarget> list = CanvasTargetCollector.GetCanvases();
  78. for (int i = 0; i < list.Count; i++)
  79. {
  80. if (list[i].canvas.gameObject.GetComponent<CanvasCollection>() == null)
  81. {
  82. list[i].canvas.gameObject.AddComponent<CanvasCollection>();
  83. list[i].canvas.gameObject.AddComponent<GraphicRaycaster>();
  84. }
  85. }
  86. ///Canvas分配wrold Camera
  87. foreach (var canvas in CanvasCollection.CanvasList) {
  88. canvas.worldCamera = RayCasterCamera;
  89. }
  90. newPos = SCInputModule.Instance.RayCasterCamera.ViewportToScreenPoint(viewportPos);
  91. // Populate initial data or drag data
  92. if(lastMousePoint3d == null) {
  93. // For the first event, use the same position for 'last' and 'new'.
  94. lastPosition = newPos;
  95. } else {
  96. // Otherwise, re-project the last pointer position.
  97. lastPosition = SCInputModule.Instance.RayCasterCamera.WorldToScreenPoint(lastMousePoint3d.Value);
  98. }
  99. // Save off the 3D position of the cursor.
  100. lastMousePoint3d = SCInputModule.Instance.RayCasterCamera.ViewportToWorldPoint(viewportPos);
  101. scPointEventData.delta = newPos - lastPosition;
  102. scPointEventData.position = newPos;
  103. if(RayCasterCamera != null && Application.platform != RuntimePlatform.Android) {
  104. Ray ray = new Ray();
  105. ray = RayCasterCamera.ScreenPointToRay(scPointEventData.position);
  106. Debug.DrawRay(ray.origin, ray.direction * maxDetectDistance, Color.blue);
  107. }
  108. }
  109. protected static RaycastResult FindFirstRaycastByDistance(List<RaycastResult> candidates) {
  110. candidates.Sort(s_RaycastComparer);
  111. return FindFirstRaycast(candidates);
  112. }
  113. private static readonly Comparison<RaycastResult> s_RaycastComparer = RaycastComparer;
  114. private static int RaycastComparer(RaycastResult lhs, RaycastResult rhs) {
  115. return lhs.distance.CompareTo(rhs.distance);
  116. }
  117. /// <summary>
  118. /// Process all mouse events.
  119. /// </summary>
  120. protected void ProcessSCEvent(SCPointEventData scPointEventData, bool isSimlate = false, RaycastResult simlateResult = new RaycastResult()) {
  121. scPointEventData.MouseButtonEventData.buttonData = scPointEventData;
  122. scPointEventData.MouseButtonEventData.buttonState = StateForMouseButton(scPointEventData.inputDevicePartBase);
  123. if(isSimlate) {
  124. scPointEventData.pointerCurrentRaycast = simlateResult;
  125. } else {
  126. eventSystem.RaycastAll(scPointEventData, m_RaycastResultCache);
  127. if (!IsRayCastResultsSortByDistance) {
  128. scPointEventData.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
  129. } else {
  130. scPointEventData.pointerCurrentRaycast = FindFirstRaycastByDistance(m_RaycastResultCache);
  131. }
  132. m_RaycastResultCache.Clear();
  133. }
  134. scPointEventData.Forward = RayCasterCamera.transform.forward;
  135. if(scPointEventData.MouseButtonEventData.PressedThisFrame() && scPointEventData.pointerCurrentRaycast.gameObject) {
  136. scPointEventData.HitPointerRelativeRayCasterCamera = RayCasterCamera.transform.InverseTransformPoint(scPointEventData.pointerCurrentRaycast.worldPosition);
  137. scPointEventData.Position3D = scPointEventData.PressPosition3D = RayCasterCamera.transform.TransformPoint(scPointEventData.HitPointerRelativeRayCasterCamera);
  138. scPointEventData.pressForward = RayCasterCamera.transform.forward;
  139. scPointEventData.DownPressGameObject = scPointEventData.pointerCurrentRaycast.gameObject;
  140. } else if(scPointEventData.MouseButtonEventData.ReleasedThisFrame()) {
  141. scPointEventData.HitPointerDeltaDragObjCenter = scPointEventData.HitPointerRelativeRayCasterCamera = scPointEventData.dragObjPosition = Vector3.zero;
  142. scPointEventData.Position3D = Vector3.zero;
  143. scPointEventData.PressPosition3D = Vector3.zero;
  144. scPointEventData.DownPressGameObject = null;
  145. scPointEventData.pressForward = Vector3.zero;
  146. scPointEventData.downtimer = 0;
  147. }
  148. if (!CanProcessEvent)
  149. {
  150. return;
  151. }
  152. if (scPointEventData.DownPressGameObject) {
  153. scPointEventData.downtimer += Time.deltaTime;
  154. scPointEventData.Position3D = RayCasterCamera.transform.TransformPoint(scPointEventData.HitPointerRelativeRayCasterCamera);
  155. }
  156. // Process the first mouse button fully
  157. ProcessMousePress(scPointEventData.MouseButtonEventData);
  158. ProcessMove(scPointEventData);
  159. if(scPointEventData.MouseButtonEventData.PressedThisFrame() && scPointEventData.pointerCurrentRaycast.gameObject && scPointEventData.pointerDrag) {
  160. ///碰撞点指向碰撞物体中心的向量
  161. scPointEventData.HitPointerDeltaDragObjCenter = scPointEventData.pointerDrag.transform.position - scPointEventData.pointerCurrentRaycast.worldPosition;
  162. ///第一次赋值 ,must
  163. scPointEventData.dragObjPosition = scPointEventData.HitPointerDeltaDragObjCenter + scPointEventData.Position3D;
  164. }
  165. ///必须在ProcessDrag前,否则,延迟一帧导致停顿感
  166. if(scPointEventData.dragging) {
  167. scPointEventData.dragObjPosition = scPointEventData.HitPointerDeltaDragObjCenter + scPointEventData.Position3D;
  168. }
  169. ///拖拽不启动阈值,否则不能触发IDragHandler
  170. //scPointEventData.useDragThreshold = false;
  171. ProcessDrag(scPointEventData);
  172. ///更新dragHitPinterPosition,必须在ProcessDrag后,ProcessDrag调用的DragHandler可能会更改PointerDrag对象的Transform
  173. if(scPointEventData.dragging) {
  174. scPointEventData.dragAnchorPosition3D = scPointEventData.pointerDrag.transform.position - scPointEventData.HitPointerDeltaDragObjCenter;
  175. } else {
  176. scPointEventData.dragAnchorPosition3D = Vector3.zero;
  177. }
  178. if(!Mathf.Approximately(scPointEventData.scrollDelta.sqrMagnitude, 0.0f)) {
  179. var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(scPointEventData.pointerCurrentRaycast.gameObject);
  180. ExecuteEvents.ExecuteHierarchy(scrollHandler, scPointEventData, ExecuteEvents.scrollHandler);
  181. }
  182. scPointEventDataxx = scPointEventData;
  183. }
  184. private static bool ShouldStartDrag(Vector3 pressPos, Vector3 currentPos, float threshold, bool useDragThreshold, PointerEventData pointerEventData) {
  185. if (useDragThreshold) {
  186. if (!useDragThreshold)
  187. return true;
  188. return (pressPos - currentPos).magnitude >= threshold * 0.0005f;
  189. }
  190. return true;
  191. }
  192. protected override void ProcessDrag(PointerEventData pointerEvent) {
  193. if(!pointerEvent.IsPointerMoving() ||
  194. Cursor.lockState == CursorLockMode.Locked ||
  195. pointerEvent.pointerDrag == null)
  196. return;
  197. if(!pointerEvent.dragging
  198. && ShouldStartDrag((pointerEvent as SCPointEventData).PressPosition3D, (pointerEvent as SCPointEventData).Position3D, eventSystem.pixelDragThreshold, pointerEvent.useDragThreshold, pointerEvent)) {
  199. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler);
  200. if (CanDrag)
  201. {
  202. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler);
  203. pointerEvent.dragging = true;
  204. }
  205. }
  206. // Drag notification
  207. if(pointerEvent.dragging) {
  208. // Before doing drag we should cancel any pointer down state
  209. // And clear selection!
  210. //&& ((pointerEvent as SCPointEventData).downtimer >= (pointerEvent as SCPointEventData).TriggerDeltaTime) ? true : false 解决3D环境下误触发Drag导致后,松开不能正常触发click的问题
  211. if (pointerEvent.pointerPress != pointerEvent.pointerDrag && ((pointerEvent as SCPointEventData).downtimer >= (pointerEvent as SCPointEventData).TriggerDeltaTime) ? true : false) {
  212. ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
  213. pointerEvent.eligibleForClick = false;
  214. pointerEvent.pointerPress = null;
  215. pointerEvent.rawPointerPress = null;
  216. }
  217. ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler);
  218. }
  219. }
  220. protected PointerEventData.FramePressState StateForMouseButton(InputDevicePartBase devicePart) {
  221. var pressed = devicePart.inputDataBase.inputKeys.GetKeyDown(InputKeyCode.Enter);
  222. var released = devicePart.inputDataBase.inputKeys.GetKeyUp(InputKeyCode.Enter);
  223. if(pressed && released)
  224. return PointerEventData.FramePressState.PressedAndReleased;
  225. if(pressed)
  226. return PointerEventData.FramePressState.Pressed;
  227. if(released)
  228. return PointerEventData.FramePressState.Released;
  229. return PointerEventData.FramePressState.NotChanged;
  230. }
  231. protected PhysicsRaycaster EnsurePhysicsRaycaster() {
  232. mPhysicsRaycaster = GetComponent<PhysicsRaycaster>();
  233. if(mPhysicsRaycaster == null) {
  234. mPhysicsRaycaster = gameObject.AddComponent<PhysicsRaycaster>();
  235. }
  236. return mPhysicsRaycaster;
  237. }
  238. protected Camera EnsureUIEventCamera(float maxDetectDistance = 30) {
  239. mRayCasterCamera = GetComponent<Camera>();
  240. if(!mRayCasterCamera) {
  241. mRayCasterCamera = gameObject.AddComponent<Camera>();
  242. }
  243. mRayCasterCamera.enabled = false;
  244. mRayCasterCamera.nearClipPlane = 0;
  245. mRayCasterCamera.farClipPlane = maxDetectDistance;
  246. mRayCasterCamera.clearFlags = CameraClearFlags.Color;
  247. mRayCasterCamera.backgroundColor = Color.black;
  248. mRayCasterCamera.orthographic = true;
  249. mRayCasterCamera.allowHDR = false;
  250. mRayCasterCamera.allowMSAA = false;
  251. mRayCasterCamera.orthographicSize = 0.1f;
  252. mRayCasterCamera.aspect = 1f;
  253. return mRayCasterCamera;
  254. }
  255. SCPointEventData scPointEventDataxx;
  256. //void OnDrawGizmos() {
  257. // if(Application.isPlaying) {
  258. // // Now show the input position.
  259. // //Gizmos.color = Color.red;
  260. // //foreach(var item in cornerLocalPostion) {
  261. // // Gizmos.DrawSphere(item, 0.01f);
  262. // //}
  263. // //Gizmos.color = Color.yellow;
  264. // //foreach(var item in midPointLocalPostion) {
  265. // // Gizmos.DrawSphere(item, 0.01f);
  266. // //}
  267. // if(scPointEventDataxx != null && scPointEventDataxx.DownPressGameObject) {
  268. // Gizmos.color = Color.black;
  269. // Gizmos.DrawSphere(scPointEventDataxx.PressPosition3D, 0.01f);
  270. // //Gizmos.color = Color.red * 0.5f;
  271. // Gizmos.DrawSphere(scPointEventDataxx.Position3D, 0.01f);
  272. // //Gizmos.color = Color.yellow * 0.5f;
  273. // if(scPointEventDataxx.pointerDrag != null) {
  274. // Gizmos.DrawSphere(scPointEventDataxx.dragObjPosition, 0.04f);
  275. // //Gizmos.color = Color.blue * 0.8f;
  276. // Gizmos.DrawSphere(scPointEventDataxx.dragAnchorPosition3D, 0.02f);
  277. // }
  278. // }
  279. // //if(scPointEventDataxx.pointerDrag)
  280. // //Gizmos.DrawSphere(scPointEventDataxx.pointerDrag.transform.position, 0.01f);
  281. // }
  282. //}
  283. }
  284. }