当前位置:   article > 正文

梳理Unity EventSystem事件系统调用过程_unity eventsystem 流程

unity eventsystem 流程

之前写过一个关于Button点击事件怎么被调用的,这次把EventSystem事件系统调用过程总结一下

                 图来自 UGUI源码分析:EventSystem事件系统_Vin129的博客-CSDN博客

在事件系统中,最重要的两个类是EventSystem与StandaloneInputModule,这两个类均继承自基类UIBehavior,而UIBehavior继承了MonoBehavior,因此这两个类是以组件的形式在Unity中执行逻辑的.

  1. public abstract class UIBehaviour : MonoBehaviour
  2. {
  3. protected virtual void Awake()
  4. {}
  5. protected virtual void OnEnable()
  6. {}
  7. protected virtual void Start()
  8. {}
  9. protected virtual void OnDisable()
  10. {}
  11. protected virtual void OnDestroy()
  12. {}
  13. /// <summary>
  14. /// Returns true if the GameObject and the Component are active.
  15. /// </summary>
  16. public virtual bool IsActive()
  17. {
  18. return isActiveAndEnabled;
  19. }
  20. #if UNITY_EDITOR
  21. protected virtual void OnValidate()
  22. {}
  23. protected virtual void Reset()
  24. {}
  25. #endif
  26. /// <summary>
  27. /// This callback is called if an associated RectTransform has its dimensions changed. The call is also made to all child rect transforms, even if the child transform itself doesn't change - as it could have, depending on its anchoring.
  28. /// </summary>
  29. protected virtual void OnRectTransformDimensionsChange()
  30. {}
  31. protected virtual void OnBeforeTransformParentChanged()
  32. {}
  33. protected virtual void OnTransformParentChanged()
  34. {}
  35. protected virtual void OnDidApplyAnimationProperties()
  36. {}
  37. protected virtual void OnCanvasGroupChanged()
  38. {}
  39. /// <summary>
  40. /// Called when the state of the parent Canvas is changed.
  41. /// </summary>
  42. protected virtual void OnCanvasHierarchyChanged()
  43. {}
  44. /// <summary>
  45. /// Returns true if the native representation of the behaviour has been destroyed.
  46. /// </summary>
  47. /// <remarks>
  48. /// When a parent canvas is either enabled, disabled or a nested canvas's OverrideSorting is changed this function is called. You can for example use this to modify objects below a canvas that may depend on a parent canvas - for example, if a canvas is disabled you may want to halt some processing of a UI element.
  49. /// </remarks>
  50. public bool IsDestroyed()
  51. {
  52. // Workaround for Unity native side of the object
  53. // having been destroyed but accessing via interface
  54. // won't call the overloaded ==
  55. return this == null;
  56. }
  57. }

首先对于EventSystem,它其中有BaseInputModule m_CurrentInputModule与 List<BaseInputModule> m_SystemInputModules均是管理输入模块的,默认情况下Unity与含有EventSystem的物体一同生成StandaloneInputModule

对于EventSystem中List<BaseInputModule> m_SystemInputModules中的对象添加是在BaseInputModule类中

  1. protected override void OnEnable()
  2. {
  3. base.OnEnable();
  4. m_EventSystem = GetComponent<EventSystem>();
  5. m_EventSystem.UpdateModules();
  6. }
  7. BaseInputModule中的OnEnable()方法
  8. public void UpdateModules()
  9. {
  10. GetComponents(m_SystemInputModules);
  11. for (int i = m_SystemInputModules.Count - 1; i >= 0; i--)
  12. {
  13. if (m_SystemInputModules[i] && m_SystemInputModules[i].IsActive())
  14. continue;
  15. m_SystemInputModules.RemoveAt(i);
  16. }
  17. }
  18. EventSystem中的OnEnable()方法

在BaseInputModule调用EventSystem的UpdateModules方法之后将对List<BaseInputModule> m_SystemInputModules进行填充,而StandaloneInputModule继承自BaseInputModule且StandaloneInputModule与EventSystem在同一个物体上,因此StandaloneInputModule被加入到EventSystem中的List<BaseInputModule> m_SystemInputModules中之后进行轮询访问.

在EventSystem中其内部的Update方法进行帧调用每一个BaseInputModule对应的方法

  1. protected virtual void Update()
  2. {
  3. if (current != this)
  4. return;
  5. TickModules();
  6. bool changedModule = false;
  7. for (var i = 0; i < m_SystemInputModules.Count; i++)
  8. {
  9. var module = m_SystemInputModules[i];
  10. if (module.IsModuleSupported() && module.ShouldActivateModule())
  11. {
  12. if (m_CurrentInputModule != module)
  13. {
  14. ChangeEventModule(module);
  15. changedModule = true;
  16. }
  17. break;
  18. }
  19. }
  20. // no event module set... set the first valid one...
  21. if (m_CurrentInputModule == null)
  22. {
  23. for (var i = 0; i < m_SystemInputModules.Count; i++)
  24. {
  25. var module = m_SystemInputModules[i];
  26. if (module.IsModuleSupported())
  27. {
  28. ChangeEventModule(module);
  29. changedModule = true;
  30. break;
  31. }
  32. }
  33. }
  34. if (!changedModule && m_CurrentInputModule != null)
  35. m_CurrentInputModule.Process();
  36. }

这里current为EventSystem类,对于EventSystem一个场景只能存在一个,EventSystem被自身类静态存储      private static List<EventSystem> m_EventSystems = new List<EventSystem>();

对于TickModules方法,该方法进行轮询上述的BaseInputModule的对应方法

  1. private void TickModules()
  2. {
  3. for (var i = 0; i < m_SystemInputModules.Count; i++)
  4. {
  5. if (m_SystemInputModules[i] != null)
  6. m_SystemInputModules[i].UpdateModule();
  7. }
  8. }
  1. public override void UpdateModule()
  2. {
  3. if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
  4. {
  5. if (m_InputPointerEvent != null && m_InputPointerEvent.pointerDrag != null && m_InputPointerEvent.dragging)
  6. {
  7. ReleaseMouse(m_InputPointerEvent, m_InputPointerEvent.pointerCurrentRaycast.gameObject);
  8. }
  9. m_InputPointerEvent = null;
  10. return;
  11. }
  12. m_LastMousePosition = m_MousePosition;
  13. m_MousePosition = input.mousePosition;
  14. }

对于EventSystem的Update方法中间部分则是为了确保该输入模块适应当前平台的保障

在EventSystem的Update方法最后执行了每个BaseInputModule的Process方法

  1. public override void Process()
  2. {
  3. if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
  4. return;
  5. bool usedEvent = SendUpdateEventToSelectedObject();
  6. // case 1004066 - touch / mouse events should be processed before navigation events in case
  7. // they change the current selected gameobject and the submit button is a touch / mouse button.
  8. // touch needs to take precedence because of the mouse emulation layer
  9. if (!ProcessTouchEvents() && input.mousePresent)
  10. ProcessMouseEvent();
  11. if (eventSystem.sendNavigationEvents)
  12. {
  13. if (!usedEvent)
  14. usedEvent |= SendMoveEventToSelectedObject();
  15. if (!usedEvent)
  16. SendSubmitEventToSelectedObject();
  17. }
  18. }

其中SendUpdateEventToSelectedObject方法将EventSystem中之前被选中的物体执行Selected事件

之后若鼠标可用将执行处理鼠标事件的方法即ProcessMouseEvent

  1. protected void ProcessMouseEvent(int id)
  2. {
  3. var mouseData = GetMousePointerEventData(id);
  4. var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;
  5. m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject;
  6. // Process the first mouse button fully
  7. ProcessMousePress(leftButtonData);
  8. ProcessMove(leftButtonData.buttonData);
  9. ProcessDrag(leftButtonData.buttonData);
  10. // Now process right / middle clicks
  11. ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
  12. ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
  13. ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
  14. ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);
  15. if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f))
  16. {
  17. var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject);
  18. ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler);
  19. }
  20. }

GetMousePointerEventData方法是在抽象类PointerInputModule中,该方法进行组装鼠标指针数据,处理这一帧与上一帧的鼠标位置信息,以处理之后的拖拽事件,在组装数据时,先是组装了鼠标左键的数据,组装中还调用了EventSystem的RaycastAll方法,该方法得到该鼠标指针位置下所有射线模块能检测到的物体,之后对于鼠标右键与中键的数据是复制了鼠标左键的数据,之后进行返回该鼠标指针数据.

在得到鼠标指针数据之后ProcessMouseEvent进行各种鼠标事件调用,将调用类型与指针数据中的射线检测到的物体传递给ExecuteEvents,在ExecuteEvents中进行各种事件的触发

总结

EventSystem中保存所有输入模块,在EventSystem的Update方法中进行轮询每个输入模块的TickModules与Process方法,其中TickModules方法将EventSystem类中的保存的选中的对象进行触发Selected事件,保存的选中的对象可在Selected类中进行设置,之后在Process方法调用后进行组装鼠标指针数据,射线检测该指针下的物体,最后在ExecuteEvents中进行各种事件调用

如果觉得文章有用请关注B站EOE组合 谢谢喵

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/127278?site
推荐阅读
相关标签
  

闽ICP备14008679号