梳理Unity EventSystem事件系统调用过程
之前写过一个关于Button点击事件怎么被调用的,这次把EventSystem事件系统调用过程总结一下
在事件系统中,最重要的两个类是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;
-
}
-
-
-
protected virtual void OnValidate()
-
{}
-
-
protected virtual void Reset()
-
{}
-
-
/// <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中进行各种事件调用
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfkhkkg
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01