SimulateMouse.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.EventSystems;
  5. using UnityEngine.UI;
  6. namespace JC.Unity {
  7. /**模拟鼠标-场景中需要存在EventSystem */
  8. public class SimulateMouse : MonoBehaviour
  9. {
  10. [SerializeField] CanvasScaler canvasScaler;
  11. [SerializeField] RectTransform mousePointer;
  12. [NonSerialized] public Action<Selectable> OnPointerEnter;
  13. [NonSerialized] public Action<Selectable> OnPointerClick;
  14. ScreenRayRaycasterUIWrapper mScreenRayRaycasterUIWrapper = new ScreenRayRaycasterUIWrapper();
  15. void Awake()
  16. {
  17. mousePointer.anchorMin = Vector2.zero;
  18. mousePointer.anchorMax = Vector2.zero;
  19. if (mScreenRayRaycasterUIWrapper != null) {
  20. // 把鼠标的位置传 Ray 发射位置
  21. mScreenRayRaycasterUIWrapper.Init(this, () => {
  22. Vector2 pos = mousePointer.anchoredPosition;
  23. pos.x *= (float) Screen.width / GetScaleScreenWidth();
  24. pos.y *= (float) Screen.height / GetScaleScreenHeight();
  25. return pos;
  26. });
  27. }
  28. }
  29. void OnDisable() {
  30. mScreenRayRaycasterUIWrapper.PressUp();
  31. }
  32. void OnEnable() {
  33. MakeMouseToScreenCenter();
  34. }
  35. void Update() {
  36. mScreenRayRaycasterUIWrapper.Update();
  37. }
  38. Vector2 ClampValue(Vector2 val)
  39. {
  40. val.x = val.x < 0 ? 0 : val.x;
  41. val.y = val.y < 0 ? 0 : val.y;
  42. float maxWidth = GetScaleScreenWidth();
  43. float maxHeight = GetScaleScreenHeight();
  44. val.x = val.x > maxWidth ? maxWidth : val.x;
  45. val.y = val.y > maxHeight ? maxHeight : val.y;
  46. return val;
  47. }
  48. #region 对外提供的接口
  49. public float GetScaleScreenWidth() {
  50. float width = Screen.width;
  51. if (canvasScaler.uiScaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize) {
  52. if (canvasScaler.screenMatchMode == CanvasScaler.ScreenMatchMode.MatchWidthOrHeight) {
  53. float height = Screen.height;
  54. if (canvasScaler.matchWidthOrHeight == 1) {
  55. width *= canvasScaler.referenceResolution.y / height;
  56. } else if (canvasScaler.matchWidthOrHeight == 0) {
  57. width = canvasScaler.referenceResolution.x;
  58. }
  59. }
  60. }
  61. return width;
  62. }
  63. public float GetScaleScreenHeight() {
  64. float height = Screen.height;
  65. if (canvasScaler.uiScaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize) {
  66. if (canvasScaler.screenMatchMode == CanvasScaler.ScreenMatchMode.MatchWidthOrHeight) {
  67. float width = Screen.width;
  68. if (canvasScaler.matchWidthOrHeight == 0) {
  69. height *= canvasScaler.referenceResolution.x / width;
  70. } else if (canvasScaler.matchWidthOrHeight == 1) {
  71. height = canvasScaler.referenceResolution.y;
  72. }
  73. }
  74. }
  75. return height;
  76. }
  77. public void MoveMousePointer(Vector2 deltaPos)
  78. {
  79. if (mousePointer == null) return;
  80. Vector2 val = mousePointer.anchoredPosition;
  81. val += deltaPos;
  82. mousePointer.anchoredPosition = ClampValue(val);
  83. }
  84. public void SetMousePointerPosition(Vector2 pos)
  85. {
  86. if (mousePointer == null) return;
  87. mousePointer.position = pos;
  88. }
  89. public void ClickMousePointer()
  90. {
  91. mScreenRayRaycasterUIWrapper.Click();
  92. }
  93. public void MakeMouseToScreenCenter() {
  94. mousePointer.anchoredPosition = new Vector2(GetScaleScreenWidth()/2,GetScaleScreenHeight()/2);
  95. }
  96. public Selectable GetCurrentSelectable() {
  97. return mScreenRayRaycasterUIWrapper.m_currentSelectable;
  98. }
  99. public void onSetNullToSelectable(Selectable target)
  100. {
  101. //mScreenRayRaycasterUIWrapper.OnSelect(target);
  102. }
  103. public void ClearSelection()
  104. {
  105. mScreenRayRaycasterUIWrapper.PressUp();
  106. }
  107. #endregion 对外提供的接口
  108. }
  109. public class ScreenRayRaycasterUIWrapper
  110. {
  111. public Selectable m_currentSelectable = null;
  112. RaycastResult m_currentRaycastResult;
  113. IPointerClickHandler m_clickHandler;
  114. IDragHandler m_dragHandler;
  115. EventSystem m_eventSystem;
  116. PointerEventData m_pointerEvent;
  117. SimulateMouse mSimulateMouse;
  118. Func<Vector2> mFunPointerPos;
  119. private bool mIsClick = false;
  120. private bool mIsPress = false;
  121. private bool mIsDrag = false;
  122. public void Init(SimulateMouse simulateMouse, Func<Vector2> funPointerPos)
  123. {
  124. mSimulateMouse = simulateMouse;
  125. m_eventSystem = EventSystem.current;
  126. m_pointerEvent = new PointerEventData(m_eventSystem);
  127. m_pointerEvent.button = PointerEventData.InputButton.Left;
  128. mFunPointerPos = funPointerPos;
  129. }
  130. static bool IsSelectableAlive(Selectable selectable)
  131. {
  132. return selectable != null && selectable;
  133. }
  134. public void Update()
  135. {
  136. m_pointerEvent.position = mFunPointerPos.Invoke();
  137. List<RaycastResult> raycastResults = new List<RaycastResult>();
  138. m_eventSystem.RaycastAll(m_pointerEvent, raycastResults);
  139. // Detect selectable
  140. bool hasRaycastSelectable = false;
  141. if (raycastResults.Count > 0)
  142. {
  143. var result = raycastResults[0]; //只检测第一个
  144. var newSelectable = result.gameObject.GetComponentInParent<Selectable>();
  145. if (IsSelectableAlive(newSelectable))
  146. {
  147. hasRaycastSelectable = true;
  148. if (newSelectable != m_currentSelectable)
  149. {
  150. Select(newSelectable);
  151. m_currentRaycastResult = result;
  152. }
  153. }
  154. }
  155. if (!hasRaycastSelectable)
  156. {
  157. if (IsSelectableAlive(m_currentSelectable))
  158. {
  159. Select(null);
  160. }
  161. else if (m_currentSelectable != null)
  162. {
  163. m_currentSelectable = null;
  164. m_clickHandler = null;
  165. m_dragHandler = null;
  166. }
  167. }
  168. if (IsSelectableAlive(m_currentSelectable))
  169. {
  170. if (m_clickHandler != null && mIsClick)
  171. {
  172. try { mSimulateMouse.OnPointerClick?.Invoke(m_currentSelectable); }
  173. catch (System.Exception e) { Debug.LogError(e.Message); }
  174. m_clickHandler.OnPointerClick(m_pointerEvent);
  175. Select(null);
  176. }
  177. else if (m_dragHandler != null && mIsPress)
  178. {
  179. mIsDrag = true;
  180. m_pointerEvent.pointerPressRaycast = m_currentRaycastResult;
  181. m_dragHandler.OnDrag(m_pointerEvent);
  182. }
  183. }
  184. mIsClick = false;
  185. }
  186. public void OnSelect(Selectable s) {
  187. Select(s);
  188. }
  189. void Select(Selectable s)
  190. {
  191. if (mIsDrag == true) return;
  192. // if (m_currentSelectable) { //退出选中
  193. // m_currentSelectable.OnPointerExit(m_pointerEvent);
  194. // }
  195. m_currentSelectable = s;
  196. if (!IsSelectableAlive(m_currentSelectable)) {
  197. m_currentSelectable = null;
  198. m_clickHandler = null;
  199. m_dragHandler = null;
  200. return;
  201. }
  202. try { mSimulateMouse.OnPointerEnter?.Invoke(m_currentSelectable); }
  203. catch (System.Exception e) { Debug.LogError(e.Message); Debug.LogError(e.StackTrace); }
  204. if (!IsSelectableAlive(m_currentSelectable)) {
  205. m_currentSelectable = null;
  206. m_clickHandler = null;
  207. m_dragHandler = null;
  208. return;
  209. }
  210. // m_currentSelectable.OnPointerEnter(m_pointerEvent); //选中
  211. m_clickHandler = m_currentSelectable.GetComponent<IPointerClickHandler>();
  212. m_dragHandler = m_currentSelectable.GetComponent<IDragHandler>();
  213. }
  214. //模拟点击
  215. public void Click() {
  216. mIsClick = true;
  217. }
  218. //模拟按下
  219. public void PressDown() {
  220. mIsClick = true;
  221. mIsPress = true;
  222. mIsDrag = false;
  223. }
  224. //模拟松开
  225. public void PressUp() {
  226. mIsClick = false;
  227. mIsPress = false;
  228. mIsDrag = false;
  229. Select(null);
  230. }
  231. }
  232. }