[AddComponentMenu("Event/Event System")] [DisallowMultipleComponent] ///<summary> /// Handles input, raycasting, and sending events. ///</summary> ///<remarks> /// The EventSystem is responsible for processing and handling events in a Unity scene. A scene should only contain one EventSystem. The EventSystem works in conjunction with a number of modules and mostly just holds state and delegates functionality to specific, overrideable components. /// When the EventSystem is started it searches for any BaseInputModules attached to the same GameObject and adds them to an internal list. On update each attached module receives an UpdateModules call, where the module can modify internal state. After each module has been Updated the active module has the Process call executed.This is where custom module processing can take place. ///</remarks> publicclassEventSystem : UIBehaviour { private List<BaseInputModule> m_SystemInputModules = new List<BaseInputModule>();
private BaseInputModule m_CurrentInputModule;
privatestatic List<EventSystem> m_EventSystems = new List<EventSystem>();
///<summary> /// Return the current EventSystem. ///</summary> publicstatic EventSystem current { get { return m_EventSystems.Count > 0 ? m_EventSystems[0] : null; } set { int index = m_EventSystems.IndexOf(value);
///<summary> /// The currently active EventSystems.BaseInputModule. ///</summary> public BaseInputModule currentInputModule { get { return m_CurrentInputModule; } }
///<summary> /// The GameObject currently considered active by the EventSystem. ///</summary> public GameObject currentSelectedGameObject { get { return m_CurrentSelected; } }
protectedEventSystem() {}
///<summary> /// Recalculate the internal list of BaseInputModules. ///</summary> publicvoidUpdateModules() { //把当前 GameObject 上所有 BaseInputModule 组件收集进 m_SystemInputModules 这个列表里,而不是返回一个新数组。 GetComponents(m_SystemInputModules); var systemInputModulesCount = m_SystemInputModules.Count; for (int i = systemInputModulesCount - 1; i >= 0; i--) { if (m_SystemInputModules[i] && m_SystemInputModules[i].IsActive()) continue;
m_SystemInputModules.RemoveAt(i); } }
privatebool m_SelectionGuard;
///<summary> /// Set the object as selected. Will send an OnDeselect the the old selected object and OnSelect to the new selected object. ///</summary> ///<param name="selected">GameObject to select.</param> ///<param name="pointer">Associated EventData.</param> publicvoidSetSelectedGameObject(GameObject selected, BaseEventData pointer) { if (m_SelectionGuard) { Debug.LogError("Attempting to select " + selected + "while already selecting an object."); return; }
private BaseEventData m_DummyData; private BaseEventData baseEventDataCache { get { if (m_DummyData == null) m_DummyData = new BaseEventData(this);
return m_DummyData; } }
///<summary> /// Set the object as selected. Will send an OnDeselect the the old selected object and OnSelect to the new selected object. ///</summary> ///<param name="selected">GameObject to select.</param> publicvoidSetSelectedGameObject(GameObject selected) { SetSelectedGameObject(selected, baseEventDataCache); }
//对射线检测产生的所有命中结果(RaycastResult)进行排序,以确定哪个 UI 元素在最“前面” privatestaticintRaycastComparer(RaycastResult lhs, RaycastResult rhs) { if (lhs.module != rhs.module) { var lhsEventCamera = lhs.module.eventCamera; var rhsEventCamera = rhs.module.eventCamera; if (lhsEventCamera != null && rhsEventCamera != null && lhsEventCamera.depth != rhsEventCamera.depth) { // need to reverse the standard compareTo if (lhsEventCamera.depth < rhsEventCamera.depth) return1; if (lhsEventCamera.depth == rhsEventCamera.depth) //这条if是防御性变成 ,保持三路比较的“完整性”,提升可读性 return0;
return-1; }
if (lhs.module.sortOrderPriority != rhs.module.sortOrderPriority) return rhs.module.sortOrderPriority.CompareTo(lhs.module.sortOrderPriority);
if (lhs.module.renderOrderPriority != rhs.module.renderOrderPriority) return rhs.module.renderOrderPriority.CompareTo(lhs.module.renderOrderPriority); }
// Renderer sorting if (lhs.sortingLayer != rhs.sortingLayer) { // Uses the layer value to properly compare the relative order of the layers. var rid = SortingLayer.GetLayerValueFromID(rhs.sortingLayer); var lid = SortingLayer.GetLayerValueFromID(lhs.sortingLayer); return rid.CompareTo(lid); }
if (lhs.sortingOrder != rhs.sortingOrder) return rhs.sortingOrder.CompareTo(lhs.sortingOrder);
//当两个命中结果来自同一个根 Canvas 时,谁的 depth 更大,谁就排在前面 // comparing depth only makes sense if the two raycast results have the same root canvas (case 912396) if (lhs.depth != rhs.depth && lhs.module.rootRaycaster == rhs.module.rootRaycaster) return rhs.depth.CompareTo(lhs.depth);
if (lhs.distance != rhs.distance) return lhs.distance.CompareTo(rhs.distance);
//处理2D 物理射线检测 // 只有项目安装了 2D Physics 包,这段代码才参与编译 #if PACKAGE_PHYSICS2D // Sorting group if (lhs.sortingGroupID != SortingGroup.invalidSortingGroupID && rhs.sortingGroupID != SortingGroup.invalidSortingGroupID) { if (lhs.sortingGroupID != rhs.sortingGroupID) return lhs.sortingGroupID.CompareTo(rhs.sortingGroupID); if (lhs.sortingGroupOrder != rhs.sortingGroupOrder) return rhs.sortingGroupOrder.CompareTo(lhs.sortingGroupOrder); } #endif
///<summary> /// Raycast into the scene using all configured BaseRaycasters. ///</summary> ///<param name="eventData">Current pointer data.</param> ///<param name="raycastResults">List of 'hits' to populate.</param> publicvoidRaycastAll(PointerEventData eventData, List<RaycastResult> raycastResults) { raycastResults.Clear(); var modules = RaycasterManager.GetRaycasters(); var modulesCount = modules.Count; for (int i = 0; i < modulesCount; ++i) { var module = modules[i]; if (module == null || !module.IsActive()) continue;
///<summary> /// Handles input, raycasting, and sending events. ///</summary> ///<remarks> /// The EventSystem is responsible for processing and handling events in a Unity scene. A scene should only contain one EventSystem. The EventSystem works in conjunction with a number of modules and mostly just holds state and delegates functionality to specific, overrideable components. /// When the EventSystem is started it searches for any BaseInputModules attached to the same GameObject and adds them to an internal list. On update each attached module receives an UpdateModules call, where the module can modify internal state. After each module has been Updated the active module has the Process call executed.This is where custom module processing can take place. ///</remarks>
private List<BaseInputModule> m_SystemInputModules = new List<BaseInputModule>();
private BaseInputModule m_CurrentInputModule;
privatestatic List<EventSystem> m_EventSystems = new List<EventSystem>();
///<summary> /// Return the current EventSystem. ///</summary> publicstatic EventSystem current { get { return m_EventSystems.Count > 0 ? m_EventSystems[0] : null; } set { int index = m_EventSystems.IndexOf(value);
Unity 的组件对象是双层结构——C# 包装对象 + C++ 原生对象。如果你直接 new EventSystem()
只创建了 C# 那一层“空壳”;
没有对应的 C++ 原生对象,没有挂到任何 GameObject 上,没有生命周期管理;
后续调用任何依赖原生层的 API 都会出问题。
2.3 具体方法
2.3.1 UpdateModules
点击展开代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
///<summary> /// Recalculate the internal list of BaseInputModules. ///</summary> publicvoidUpdateModules() { //把当前 GameObject 上所有 BaseInputModule 组件收集进 m_SystemInputModules 这个列表里,而不是返回一个新数组。 GetComponents(m_SystemInputModules); var systemInputModulesCount = m_SystemInputModules.Count; for (int i = systemInputModulesCount - 1; i >= 0; i--) { if (m_SystemInputModules[i] && m_SystemInputModules[i].IsActive()) continue;
///<summary> /// Set the object as selected. Will send an OnDeselect the the old selected object and OnSelect to the new selected object. ///</summary> ///<param name="selected">GameObject to select.</param> ///<param name="pointer">Associated EventData.</param> publicvoidSetSelectedGameObject(GameObject selected, BaseEventData pointer) { if (m_SelectionGuard) { Debug.LogError("Attempting to select " + selected + "while already selecting an object."); return; }
private BaseEventData m_DummyData; private BaseEventData baseEventDataCache { get { if (m_DummyData == null) m_DummyData = new BaseEventData(this);
return m_DummyData; } }
// <summary> /// Set the object as selected. Will send an OnDeselect the the old selected object and OnSelect to the new selected object. ///</summary> ///<param name="selected">GameObject to select.</param> publicvoidSetSelectedGameObject(GameObject selected) { SetSelectedGameObject(selected, baseEventDataCache); }
//对射线检测产生的所有命中结果(RaycastResult)进行排序,以确定哪个 UI 元素在最“前面” privatestaticintRaycastComparer(RaycastResult lhs, RaycastResult rhs) { if (lhs.module != rhs.module) { var lhsEventCamera = lhs.module.eventCamera; var rhsEventCamera = rhs.module.eventCamera; if (lhsEventCamera != null && rhsEventCamera != null && lhsEventCamera.depth != rhsEventCamera.depth) { // need to reverse the standard compareTo if (lhsEventCamera.depth < rhsEventCamera.depth) return1; if (lhsEventCamera.depth == rhsEventCamera.depth) //这条if是防御性变成 ,保持三路比较的“完整性”,提升可读性 return0;
return-1; }
if (lhs.module.sortOrderPriority != rhs.module.sortOrderPriority) return rhs.module.sortOrderPriority.CompareTo(lhs.module.sortOrderPriority);
if (lhs.module.renderOrderPriority != rhs.module.renderOrderPriority) return rhs.module.renderOrderPriority.CompareTo(lhs.module.renderOrderPriority); }
// Renderer sorting if (lhs.sortingLayer != rhs.sortingLayer) { // Uses the layer value to properly compare the relative order of the layers. var rid = SortingLayer.GetLayerValueFromID(rhs.sortingLayer); var lid = SortingLayer.GetLayerValueFromID(lhs.sortingLayer); return rid.CompareTo(lid); }
if (lhs.sortingOrder != rhs.sortingOrder) return rhs.sortingOrder.CompareTo(lhs.sortingOrder);
//当两个命中结果来自同一个根 Canvas 时,谁的 depth 更大,谁就排在前面 // comparing depth only makes sense if the two raycast results have the same root canvas (case 912396) if (lhs.depth != rhs.depth && lhs.module.rootRaycaster == rhs.module.rootRaycaster) return rhs.depth.CompareTo(lhs.depth);
if (lhs.distance != rhs.distance) return lhs.distance.CompareTo(rhs.distance);
//处理2D 物理射线检测 // 只有项目安装了 2D Physics 包,这段代码才参与编译 #if PACKAGE_PHYSICS2D // Sorting group if (lhs.sortingGroupID != SortingGroup.invalidSortingGroupID && rhs.sortingGroupID != SortingGroup.invalidSortingGroupID) { if (lhs.sortingGroupID != rhs.sortingGroupID) return lhs.sortingGroupID.CompareTo(rhs.sortingGroupID); if (lhs.sortingGroupOrder != rhs.sortingGroupOrder) return rhs.sortingGroupOrder.CompareTo(lhs.sortingGroupOrder); } #endif
///<summary> /// Raycast into the scene using all configured BaseRaycasters. ///</summary> ///<param name="eventData">Current pointer data.</param> ///<param name="raycastResults">List of 'hits' to populate.</param> publicvoidRaycastAll(PointerEventData eventData, List<RaycastResult> raycastResults) { raycastResults.Clear(); var modules = RaycasterManager.GetRaycasters(); var modulesCount = modules.Count; for (int i = 0; i < modulesCount; ++i) { var module = modules[i]; if (module == null || !module.IsActive()) continue;