UGUI源码-事件系统-3

文章详细解析了UnityUGUI中的事件系统,特别是如何处理鼠标交互,包括鼠标点击、移动和拖拽等操作,以及ButtonClick事件从触发到执行的详细流程。
摘要由CSDN通过智能技术生成

事件系统-输入模块

问题:为什么UI中的元素可以交互?

在这里插入图片描述

Button Click触发过程

在这里插入图片描述

  1. 调试
    在这里插入图片描述
  2. 点击按钮
    在这里插入图片描述
  3. 调用堆栈
    在这里插入图片描述
  4. Update方法
    在这里插入图片描述
  5. ProcessMouseEvent()函数来处理鼠标事件
    在这里插入图片描述
 protected void ProcessMouseEvent()
 {
     ProcessMouseEvent(0);
 }
  1. ProcessMouseEvent(0)方法
    在这里插入图片描述
protected void ProcessMouseEvent(int id)
{
	//通过 mouseData 获取鼠标左键的按钮状态数据
    var mouseData = GetMousePointerEventData(id);
    var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;
	//设置当前焦点游戏对象为鼠标指针当前射线检测到的游戏对象
    m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject;

    //处理鼠标左键的按下事件
    ProcessMousePress(leftButtonData);
    //处理鼠标移动事件
    ProcessMove(leftButtonData.buttonData);
    //处理鼠标拖拽事件
    ProcessDrag(leftButtonData.buttonData);

    // 处理右键和中键点击事件,分别调用 ProcessMousePress 和 ProcessDrag
    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);
    }
}
  1. 进入到鼠标左键点击的按下事件ProcessMousePress(leftButtonData)方法里,通过调用 ReleaseMouse 方法,可以在释放鼠标时执行一些操作
    在这里插入图片描述
protected void ProcessMousePress(MouseButtonEventData data)
{
    var pointerEvent = data.buttonData;
    var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;

    // PointerDown notification
    if (data.PressedThisFrame())
    {
        pointerEvent.eligibleForClick = true;
        pointerEvent.delta = Vector2.zero;
        pointerEvent.dragging = false;
        pointerEvent.useDragThreshold = true;
        pointerEvent.pressPosition = pointerEvent.position;
        pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;

        DeselectIfSelectionChanged(currentOverGo, pointerEvent);

        var resetDiffTime = Time.unscaledTime - pointerEvent.clickTime;
        if (resetDiffTime >= doubleClickTime)
        {
            pointerEvent.clickCount = 0;
        }

        // search for the control that will receive the press
        // if we can't find a press handler set the press
        // handler to be what would receive a click.
        var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
        var newClick = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);

        // didnt find a press handler... search for a click handler
        if (newPressed == null)
            newPressed = newClick;

        // Debug.Log("Pressed: " + newPressed);

        float time = Time.unscaledTime;

        if (newPressed == pointerEvent.lastPress)
        {
            var diffTime = time - pointerEvent.clickTime;
            if (diffTime < doubleClickTime)
                ++pointerEvent.clickCount;
            else
                pointerEvent.clickCount = 1;

            pointerEvent.clickTime = time;
        }
        else
        {
            pointerEvent.clickCount = 1;
        }

        pointerEvent.pointerPress = newPressed;
        pointerEvent.rawPointerPress = currentOverGo;
        pointerEvent.pointerClick = newClick;

        pointerEvent.clickTime = time;

        // Save the drag handler as well
        pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);

        if (pointerEvent.pointerDrag != null)
            ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);

        m_InputPointerEvent = pointerEvent;
    }

    // PointerUp notification
    if (data.ReleasedThisFrame())
    {
        ReleaseMouse(pointerEvent, currentOverGo);
    }
}
  1. ReleaseMouse方法

在这里插入图片描述

//pointerEvent是鼠标当前事件里面存储的一些数据
private void ReleaseMouse(PointerEventData pointerEvent, GameObject currentOverGo)
{
	//ExecuteEvents.Execute 方法执行指针按下处理器的指针抬起事件(pointerUpHandler)
    ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
	// 获取当前射线检测到的游戏对象上的指针点击处理器
    var pointerClickHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);

	//如果指针点击处理器与指针事件中的 pointerClick 相同,并且事件符合点击条件(eligibleForClick 为 true),则执行指针点击处理器的指针点击事件(pointerClickHandler)
    // PointerClick and Drop events
    if (pointerEvent.pointerClick == pointerClickHandler && pointerEvent.eligibleForClick)
    {
        ExecuteEvents.Execute(pointerEvent.pointerClick, pointerEvent, ExecuteEvents.pointerClickHandler);
    }
    //如果存在指针拖拽目标并且正在拖拽中,则通过 ExecuteEvents.ExecuteHierarchy 方法执行指定对象上的拖拽处理器的放置事件(dropHandler)
    if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
    {
        ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
    }
	//重置指针事件的一些属性,包括取消点击条件、清除指针按下对象
    pointerEvent.eligibleForClick = false;
    pointerEvent.pointerPress = null;
    pointerEvent.rawPointerPress = null;
    pointerEvent.pointerClick = null;
	//如果存在指针拖拽目标并且正在拖拽中,则执行指针拖拽处理器的结束拖拽事件(endDragHandler)
    if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
        ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
	//将指针事件的拖拽状态和拖拽对象重置为 false 和 null
    pointerEvent.dragging = false;
    pointerEvent.pointerDrag = null;

    // redo pointer enter / exit to refresh state
    // so that if we moused over something that ignored it before
    // due to having pressed on something else
    // it now gets it.
    //重新处理指针进入和离开事件,以刷新状态,确保当前射线检测到的游戏对象的状态正确更新
    if (currentOverGo != pointerEvent.pointerEnter)
    {
        HandlePointerExitAndEnter(pointerEvent, null);
        HandlePointerExitAndEnter(pointerEvent, currentOverGo);
    }
	//将更新后的指针事件赋值给 m_InputPointerEvent
    m_InputPointerEvent = pointerEvent;
}
  1. ExecuteEvents.Execute方法
    Ex
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;
}

在这里插入图片描述

  1. Excute方法,专门执行 IPointerClickHandler 接口的 OnPointerClick 方法,面向接口编程,谁实现接口,谁来做这件事情
//它接受两个参数:一个实现了 IPointerClickHandler 接口的对象 handler 和一个基本事件数据对象 eventData
private static void Execute(IPointerClickHandler handler, BaseEventData eventData)
{
    handler.OnPointerClick(ValidateEventData<PointerEventData>(eventData));
}
  1. 用于处理指针点击事件(例如鼠标点击、触摸点击)
    在这里插入图片描述
 public virtual void OnPointerClick(PointerEventData eventData)
 {
     if (eventData.button != PointerEventData.InputButton.Left)
         return;

     Press();
 }
  1. Press方法,调用了按钮的点击事件委托 m_OnClick 的 Invoke 方法,触发了按钮的点击事件。这意味着与该按钮相关联的所有点击事件监听器都会收到通知,并执行相应的操作在这里插入图片描述
 private void Press()
 {
     Debug.Log("点击按钮");
     //检查按钮是否处于激活状态且可交互
     if (!IsActive() || !IsInteractable())
         return;
	//用于添加性能分析标记,以便在性能分析工具中跟踪按钮点击事件
     UISystemProfilerApi.AddMarker("Button.onClick", this);
     //调用了按钮的点击事件委托 m_OnClick 的 Invoke 方法,触发了按钮的点击事件。这意味着与该按钮相关联的所有点击事件监听器都会收到通知,并执行相应的操作
     m_OnClick.Invoke();
 }

在这里插入图片描述

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: UGUI是指“User Graphic User Interface”,可以翻译为用户图形界面。它是一种用户与计算机进行交互的方式,通常以图标、按钮、菜单等可视化元素的形式展现给用户。UGUI可以让用户通过简单直观的操作完成复杂的任务,提高了用户对计算机的使用体验。 Sci-Fi是指“Science Fiction”的缩写,可以翻译为科幻。科幻是一种虚构文学和电影类型,通过科学以及科技的发展为基础,探讨未来世界的可能性。科幻作品中会出现各种前所未有的科技设备、想象力丰富的场景和故事情节,旨在激发人们对未来和科学的好奇心。 UGUI与Sci-Fi可以结合在一起,形成创新的应用。比如在虚拟现实和增强现实领域中,UGUI可以为用户提供直观的操作界面,让用户更加方便地体验科幻故事中的虚拟环境。同时,UGUI的发展也可以受到科幻作品的启发,将更多的创新科技融入到用户界面设计中,提供更加便捷、智能的交互方式。 总之,UGUI和Sci-Fi的结合展现出了前所未有的潜力。它们的共同点是都关注和探索人与科技的互动方式,为我们的生活和工作带来了很多创新的可能。通过不断的研究和创新,我们可以期待在未来看到更多的UGUI sci-fi应用的出现,为人们带来更加便捷、智能、令人惊叹的体验。 ### 回答2: UGUI是什么?UGUIUnity GUI)是一种用于游戏开发的图像用户界面(GUI系统。它是Unity引擎的一部分,提供了一系列用于创建游戏界面的工具和组件。 科幻(Sci-Fi)是指科学幻想的缩写,是一种虚构的文学和电影风格,主要关注科学技术的发展和未来社会的设想。 UGUI Sci-Fi是将这两个元素融合在一起。在游戏开发中,UGUI可用于创建科幻题材的界面,为游戏增添视觉效果和交互体验。使用UGUI可以自定义各种科幻元素,例如虚拟屏幕、炫酷的按钮、分析仪表盘等,使游戏界面更具科幻风格。 UGUI Sci-Fi的应用不仅仅局限于游戏开发。随着虚拟现实(VR)和增强现实(AR)技术的发展,越来越多的人开始使用UGUI Sci-Fi来创建虚拟界面和用户交互体验。这些界面可以用于虚拟现实游戏、科幻主题的交互式体验以及其他科技展示和演示。 UGUI Sci-Fi的潜力是巨大的。它提供了一个创造性的平台,使得开发者能够通过虚构的科幻元素来打造独特的用户界面和用户体验。无论是在游戏开发还是其他领域,UGUI Sci-Fi都可以为用户带来沉浸式、刺激性和独特的视觉效果,让人们更好地体验科幻世界的魅力。 ### 回答3: UGUI是什么?UGUIUnity游戏开发引擎中的一种图形用户界面系统,可用于创建游戏中的界面元素。 Sci-fi是什么?Sci-fi是科幻的缩写,指的是科幻小说、电影、游戏等作品的内容和风格。 结合起来,UGUI Sci-fi就是利用UGUI系统来创建科幻风格的游戏界面元素的意思。 在开发游戏时,选择适合游戏风格的界面元素对于营造游戏氛围和玩家体验非常重要。科幻题材的游戏通常具有未来感和高科技的特点,因此在界面设计上需要展现出这种风格。UGUI系统提供了丰富的功能和灵活的设计工具,使得开发者可以轻松创建出符合科幻风格的游戏界面。 使用UGUI Sci-fi可以在游戏中展现出虚拟的科技感,例如使用高科技设计的按钮、界面元素带有流光效果、炫酷的过渡动画等。这些元素可以为玩家创造出一个令人身临其境的科幻世界,增强游戏的视觉吸引力和沉浸感。 总而言之,UGUI Sci-fi是一种利用UGUI系统来创建科幻风格游戏界面元素的方法,通过精心设计的界面元素可以提升游戏的视觉效果,为玩家带来更好的游戏体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值