顶层上来看EventSystem继承于UIBehaviour,UIBehaviour继承于Monobehavior所有包含了Update等方法。Update方法首先更新输入模块状态,然后选定当前可用的输入模块,最后调用输入模块的Process方法。
protected virtual void Update()
{
if (current != this)
return;
TickModules();//该方法用于更新输入模块的状态,例如鼠标的位置
bool changedModule = false;
var systemInputModulesCount = m_SystemInputModules.Count;
for (var i = 0; i < systemInputModulesCount; 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 < systemInputModulesCount; i++)
{
var module = m_SystemInputModules[i];
if (module.IsModuleSupported())
{
ChangeEventModule(module);
changedModule = true;
break;
}
}
}
if (!changedModule && m_CurrentInputModule != null)
m_CurrentInputModule.Process();//上面两个循环用于确定使用哪个输入模块,Process方法用//于发送事件
输入模块以StandaloneInputModule为例。StandaloneInputModule中的Process方法如下:其中ProcessMouseEvent用于发送鼠标事件,ProcessMouseEvent方法首先通过GetMousePointerEventData方法会调用射线检测确定当前选中的GameObject,然后会处理鼠标按压、移动、拖拽等事件。Process方法中的SendXXXEventToSelectedObject方法负责通知EventSystem中当前被选中的物体执行相应事件。
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();
}
}
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);
}
}
最主要关注这一个方法。
ExecuteEvents.Execute(pointerEvent.pointerDrag,pointerEvent,ExecuteEvents.initializePotentialDrag);
Execute方法就是执行事件。我们跳转到Execute的定义可以发现它包含三个参数,第一个参数为target是GameObject类型,第二个参数主要包含了事件的一些信息,第三个参数类型为EventFuction<T>是一个委托,定义如下:
public delegate void EventFunction<T1>(T1 handler, BaseEventData eventData);
所以可以很容易分析出Execute方法的功能
1:首先找到target (GameObject)中类型为T(一个接口)的component,保存到internalHandlers中
2:然后遍历internalHandlers这个List,执行 functor
3:functor有很多重载会根据输入的类型T,去执行T接口中的对应方法。
private static readonly EventFunction<IPointerDownHandler> s_PointerDownHandler = Execute;
private static void Execute(IPointerDownHandler handler, BaseEventData eventData)
{
handler.OnPointerDown(ValidateEventData<PointerEventData>(eventData));
}
所以在使用的时候我们只需要在脚本中实现这些方法就可以被事件调用了。综上所示EventSystem分析完毕。
public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
{
var internalHandlers = ListPool<IEventSystemHandler>.Get();
GetEventList<T>(target, internalHandlers);
// if (s_InternalHandlers.Count > 0)
// Debug.Log("Executinng " + typeof (T) + " on " + target);
var internalHandlersCount = internalHandlers.Count;
for (var i = 0; i < internalHandlersCount; i++)
{
T arg;
try
{
arg = (T)internalHandlers[i];
}
catch (Exception e)
{
var temp = internalHandlers[i];
Debug.LogException(new Exception(string.Format("Type {0} expected {1} received.", typeof(T).Name, temp.GetType().Name), e));
continue;
}
try
{
functor(arg, eventData);
}
catch (Exception e)
{
Debug.LogException(e);
}
}
var handlerCount = internalHandlers.Count;
ListPool<IEventSystemHandler>.Release(internalHandlers);
return handlerCount > 0;
}