赞
踩
之前写过一个关于Button点击事件怎么被调用的,这次把EventSystem事件系统调用过程总结一下
图来自 UGUI源码分析:EventSystem事件系统_Vin129的博客-CSDN博客
在事件系统中,最重要的两个类是EventSystem与StandaloneInputModule,这两个类均继承自基类UIBehavior,而UIBehavior继承了MonoBehavior,因此这两个类是以组件的形式在Unity中执行逻辑的.
- public abstract class UIBehaviour : MonoBehaviour
- {
- protected virtual void Awake()
- {}
-
- protected virtual void OnEnable()
- {}
-
- protected virtual void Start()
- {}
-
- protected virtual void OnDisable()
- {}
-
- protected virtual void OnDestroy()
- {}
-
- /// <summary>
- /// Returns true if the GameObject and the Component are active.
- /// </summary>
- public virtual bool IsActive()
- {
- return isActiveAndEnabled;
- }
-
- #if UNITY_EDITOR
- protected virtual void OnValidate()
- {}
-
- protected virtual void Reset()
- {}
- #endif
- /// <summary>
- /// 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.
- /// </summary>
- protected virtual void OnRectTransformDimensionsChange()
- {}
-
- protected virtual void OnBeforeTransformParentChanged()
- {}
-
- protected virtual void OnTransformParentChanged()
- {}
-
- protected virtual void OnDidApplyAnimationProperties()
- {}
-
- protected virtual void OnCanvasGroupChanged()
- {}
-
- /// <summary>
- /// Called when the state of the parent Canvas is changed.
- /// </summary>
- protected virtual void OnCanvasHierarchyChanged()
- {}
-
- /// <summary>
- /// Returns true if the native representation of the behaviour has been destroyed.
- /// </summary>
- /// <remarks>
- /// 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.
- /// </remarks>
- public bool IsDestroyed()
- {
- // Workaround for Unity native side of the object
- // having been destroyed but accessing via interface
- // won't call the overloaded ==
- return this == null;
- }
- }
首先对于EventSystem,它其中有BaseInputModule m_CurrentInputModule与 List<BaseInputModule> m_SystemInputModules均是管理输入模块的,默认情况下Unity与含有EventSystem的物体一同生成StandaloneInputModule
对于EventSystem中List<BaseInputModule> m_SystemInputModules中的对象添加是在BaseInputModule类中
- protected override void OnEnable()
- {
- base.OnEnable();
- m_EventSystem = GetComponent<EventSystem>();
- m_EventSystem.UpdateModules();
- }
-
- BaseInputModule中的OnEnable()方法
-
-
- public void UpdateModules()
- {
- GetComponents(m_SystemInputModules);
- for (int i = m_SystemInputModules.Count - 1; i >= 0; i--)
- {
- if (m_SystemInputModules[i] && m_SystemInputModules[i].IsActive())
- continue;
-
- m_SystemInputModules.RemoveAt(i);
- }
- }
-
- EventSystem中的OnEnable()方法
在BaseInputModule调用EventSystem的UpdateModules方法之后将对List<BaseInputModule> m_SystemInputModules进行填充,而StandaloneInputModule继承自BaseInputModule且StandaloneInputModule与EventSystem在同一个物体上,因此StandaloneInputModule被加入到EventSystem中的List<BaseInputModule> m_SystemInputModules中之后进行轮询访问.
在EventSystem中其内部的Update方法进行帧调用每一个BaseInputModule对应的方法
- protected virtual void Update()
- {
- if (current != this)
- return;
- TickModules();
-
- bool changedModule = false;
- for (var i = 0; i < m_SystemInputModules.Count; i++)
- {
- var module = m_SystemInputModules[i];
- if (module.IsModuleSupported() && module.ShouldActivateModule())
- {
- if (m_CurrentInputModule != module)
- {
- ChangeEventModule(module);
- changedModule = true;
- }
- break;
- }
- }
-
- // no event module set... set the first valid one...
- if (m_CurrentInputModule == null)
- {
- for (var i = 0; i < m_SystemInputModules.Count; i++)
- {
- var module = m_SystemInputModules[i];
- if (module.IsModuleSupported())
- {
- ChangeEventModule(module);
- changedModule = true;
- break;
- }
- }
- }
-
- if (!changedModule && m_CurrentInputModule != null)
- m_CurrentInputModule.Process();
- }
这里current为EventSystem类,对于EventSystem一个场景只能存在一个,EventSystem被自身类静态存储 private static List<EventSystem> m_EventSystems = new List<EventSystem>();
对于TickModules方法,该方法进行轮询上述的BaseInputModule的对应方法
- private void TickModules()
- {
- for (var i = 0; i < m_SystemInputModules.Count; i++)
- {
- if (m_SystemInputModules[i] != null)
- m_SystemInputModules[i].UpdateModule();
- }
- }
- public override void UpdateModule()
- {
- if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
- {
- if (m_InputPointerEvent != null && m_InputPointerEvent.pointerDrag != null && m_InputPointerEvent.dragging)
- {
- ReleaseMouse(m_InputPointerEvent, m_InputPointerEvent.pointerCurrentRaycast.gameObject);
- }
-
- m_InputPointerEvent = null;
-
- return;
- }
-
- m_LastMousePosition = m_MousePosition;
- m_MousePosition = input.mousePosition;
- }
对于EventSystem的Update方法中间部分则是为了确保该输入模块适应当前平台的保障
在EventSystem的Update方法最后执行了每个BaseInputModule的Process方法
- public override void Process()
- {
- if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
- return;
-
- bool usedEvent = SendUpdateEventToSelectedObject();
-
- // case 1004066 - touch / mouse events should be processed before navigation events in case
- // they change the current selected gameobject and the submit button is a touch / mouse button.
-
- // touch needs to take precedence because of the mouse emulation layer
- if (!ProcessTouchEvents() && input.mousePresent)
- ProcessMouseEvent();
-
- if (eventSystem.sendNavigationEvents)
- {
- if (!usedEvent)
- usedEvent |= SendMoveEventToSelectedObject();
-
- if (!usedEvent)
- SendSubmitEventToSelectedObject();
- }
- }
其中SendUpdateEventToSelectedObject方法将EventSystem中之前被选中的物体执行Selected事件
之后若鼠标可用将执行处理鼠标事件的方法即ProcessMouseEvent
- protected void ProcessMouseEvent(int id)
- {
- var mouseData = GetMousePointerEventData(id);
- var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;
-
- m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject;
-
- // Process the first mouse button fully
- ProcessMousePress(leftButtonData);
- ProcessMove(leftButtonData.buttonData);
- ProcessDrag(leftButtonData.buttonData);
-
- // Now process right / middle clicks
- ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
- ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
- ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
- ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);
-
- if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f))
- {
- var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject);
- ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler);
- }
- }
GetMousePointerEventData方法是在抽象类PointerInputModule中,该方法进行组装鼠标指针数据,处理这一帧与上一帧的鼠标位置信息,以处理之后的拖拽事件,在组装数据时,先是组装了鼠标左键的数据,组装中还调用了EventSystem的RaycastAll方法,该方法得到该鼠标指针位置下所有射线模块能检测到的物体,之后对于鼠标右键与中键的数据是复制了鼠标左键的数据,之后进行返回该鼠标指针数据.
在得到鼠标指针数据之后ProcessMouseEvent进行各种鼠标事件调用,将调用类型与指针数据中的射线检测到的物体传递给ExecuteEvents,在ExecuteEvents中进行各种事件的触发
总结
EventSystem中保存所有输入模块,在EventSystem的Update方法中进行轮询每个输入模块的TickModules与Process方法,其中TickModules方法将EventSystem类中的保存的选中的对象进行触发Selected事件,保存的选中的对象可在Selected类中进行设置,之后在Process方法调用后进行组装鼠标指针数据,射线检测该指针下的物体,最后在ExecuteEvents中进行各种事件调用
如果觉得文章有用请关注B站EOE组合 谢谢喵
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。