(三)UGUI源码分析之输入模块

目前来看,下面的总结可能只是属于一种草稿版,后期会修改为比较简单易懂的版本,不过你想看的话可以结合源码进行理解我到底在说什么。

 

更新时间:2020年2月17日22:03:10

着重说明部分流程,针对从EventSystem的OnUpdate方法执行的输入模块Process方法说明,相关链接可看https://blog.csdn.net/qq_39574690/article/details/104330990

PS:[D,  A]物体链是指 A->B->C->D父子关系链,从D最终子物体一直遍历到A物体的意思。
信息综合体是指PointerEventData类
 。

StandaloneInputModule类和TouchInputModule类分别都实现了Process方法,下面以 StandaloneInputModule类为例说明。
1、在Window、Linux、MacOSX系统上非编辑器运行时,若游戏没有处于激活窗口时,则不会进行任何操作;
2、发送OnUpdateSelected消息给正在被选中的物体
3、检查Input.mousePresent(鼠标设备是否被检测到)为true 且 处理TouchEvent失败后 执行处理MouseEvent
  3.1、TouchEvent处理:遍历所有Touch对象,排除type为TouchType.Indirect的对象不进行处理,将touch对象传入一个方法GetTouchPointerEventData(touch, out pressed, out released); 进如下操作:
      3.1.1 针对GetTouchPointerEventData分析:根据touch.fingerId获取到一个PointerEventData(包含点击位置信息、帧之间的点击距离、鼠标按键标记(Left,Right,Middle)等等的输入信息结合体),此处获取到的可能是全新的输入信息结合体也可能是上一帧的输入信息结合体,接着更新输入信息结合体PointEventData的位置等信息,判断touch.phase不等于TouchPhase.Canceled时会进行利用EventSystem的RaycastAll方法,从摄像机往鼠标方向射线检测出所有碰到的物体信息,拿到第一个物体信息(RaycastResult)存入信息综合体PointEventData中,最后将信息综合体返回给外部。
   继续3.1解释:从3.1.1获取到的信息综合体里存有关键的位置信息和射线检测到的第一个物体信息,以及pressed(是否按下鼠标)和released(是否松开鼠标)两个标记位,接着调用了ProcessTouchPress(信息综合体, pressed, released)方法。
     3.1.2 针对ProcessTouchPress方法分析:
       ①若鼠标按下pressed为true,进行更新信息综合体的一些其他信息(如:帧之间的点击距离、是否拖动标记、是否使用拖动阻力、鼠标按下位置等等),调用DeselectIfSelectionChanged方法检查当前鼠标按下指向的物体是否是新物体,如果是新物体则往原本选中的物体发送OnDeselect消息,并将当前选中物体置空,接着判断当前鼠标指向的物体,若和之前不一样,则进行调用HandlePointerExitAndEnter方法,方法会选择出原本指向物体和新指向物体的共同父物体,先对[原本指向物体, 共同父物体下一级物体]这一物体组发送PointerExit消息,再对[新指向物体, 共同父物体下一级]这一物体组发送PointerEnter消息(物体组意思是从原本指向物体一直往上搜到共同父物体下一级物体这部分范围内都算物体组),接着是处理当前鼠标按下的物体的PointerDown消息发送,如果无法处理,则进行会强行用可以物体链上可处理PointerClick消息的物体作为信息综合体的按下物体,最终检查当前鼠标按下物体若有继承IDragHandler,则向物体发送OnInitializePotentialDrag消息。
        ②若鼠标抬起released为true, 会向当前鼠标抬起的物体发送PointerUp消息,检查当前鼠标抬起的物体和之前鼠标按下的物体是否同一个物体,若是则向物体发送PointerClick消息;若不是同一个物体,检查是否拥有拖拽的物体,若有且正在拖拽中,则向鼠标抬起时指向的物体发送Drop消息,接着重置一些信息综合体的参数和继续检查到有拖拽物体且正在拖拽中,向拖拽物体发送EndDrag消息,最后对鼠标进入时的物体发送PointerExit消息。
   继续3.1解释:若没有抬起鼠标,则调用ProcessMove(信息综合体)进行处理进入新物体和离开旧物理的PointerEnter和PointerExit消息发送,但是实际上我观察发现之前3.1.2就已经进行了处理!所以这里是不会再进行的了。然后调用ProcessDrag(信息综合体)进行检查是否需要对拖拽物体发送DragBegin消息(只有在没有进行拖拽时且允许拖拽时才会发送),若正在拖拽中,进行检查正在拖拽的物体和鼠标按下时的物体,若它们不相同,则对鼠标按下的物体发送PointerUp消息(意味着强制对之前按下的物体释放)。然后对拖拽的物体发送Drag消息(记得②上面也说到过)
      若已经抬起鼠标了,则从释放该信息综合体PointerEventData(说明信息综合体是在鼠标按下时创建,鼠标松开后注销)
至此,结束整个ProcessTouchEvents方法,如果touchCount>0返回true,否则返回false
   3.2 若当前不是触屏,而是PC端,则会进行ProcessMouseEvent方法.
     3.2.1 调用GetMousePointerEventData(0)方法,获取上一帧的鼠标左键信息综合体,设置信息综合体的鼠标位置、帧之间的鼠标距离、滚轮滚动距离、按钮类型信息,调用EventSystem的RaycastAll方法获取到所有的射线检测到的物体信息(RaycastResult),再取出第一个物体信息将其存入信息综合体。然后获取鼠标右键、鼠标滚轮信息综合体,将已经设置好的鼠标左键综合体的内容拷贝到它们2个身上。最后,将这3个信息综合体再次封装为 {鼠标按键类型(左,滚轮,右),鼠标按键状态(按下,松开,按下&松开),  对应的信息综合体 }(以lua表形式表达封装)将其作为列表,存入一个MouseState类中,最后返回这个类对象。
    继续3.2分析:从3.2.1获取到的一个MouseState中存有鼠标三个按键(左、滚轮、右)的信息综合体,然后从中获取到鼠标左键信息综合体中射线检测到的第一个物体作为当前输入模块的被聚焦物体,处理鼠标按下操作ProcessMousePress。
    3.2.2 分析调用ProcessMousePress:检查鼠标按键是否被按下,①若鼠标按键按下,则更新信息综合体信息(如当前帧是否可能被点击标记位,帧之间鼠标距离,是否拖拽中,按下位置,按下射线信息、计算点击次数,点击时间戳等),检查当前鼠标指向物体和原本选中物体是否相同,若不同则调用EventSystem的SetSelectedGameObject(null, pointer)告诉事件系统向原本选中物体发送OnDeselect消息和置空选中物体对象;然后,对鼠标指向的物体发送PointerDown消息,若成功则设置信息综合体的按下时物体为处理了PointerDown消息的物体,否则向鼠标指向的物体寻找一个可处理PointerClick消息的物体作为按下物体;若鼠标指向的物体链存在一个可处理Drag消息的物体,则向该物体发送OnInitializePotentialDrag消息;最后设置输入模块的当前输入信息综合体为鼠标左键信息综合体。
       ②若松开鼠标按键,调用 ReleaseMouse(pointerEvent, currentOverGo); 传入的是信息综合体和当前鼠标指向的物体,方法先进行向鼠标按下时的物体发送PointerUp消息,检查符合点击条件时向鼠标按下时的物体发送PointerClick消息,若没有满足点击条件且满足拖拽条件时,向鼠标指向物体发送Drop消息;若满足拖拽条件则向拖拽物体发送EndDrag消息;若满足鼠标指向物体和鼠标进入时的物体不相同,则将鼠标信息综合体持有的(已发送PointerEnter,未发送PointerExit)物体发送PointerExit消息,再继续向[原本进入时物体,共同父物体下一级]物体链发送PointerExit,向[新进入时物体, 共同父物体下一级]物体链发送PointerEnter消息。(但是我发现实际上源码有误,不会执行PointerEnter,只会执行PointerExit消息),最后更新当前输入模块的信息综合体。
  继续3.2分析:调用ProcessMove(左键信息综合体)和ProcessDrag(左键信息综合体)。
       3.2.3 分析ProcessMove():若鼠标没被锁定,则进行调用HandlePointerExitAndEnter(PointerEventData currentPointerData, GameObject newEnterTarget),方法会进行判断信息综合体上原本的进入时鼠标指向物体和新的鼠标进入物体,若它们不相同则向[原本物体, 共同父物体下一级]物体链发送PointerExit,向[新的鼠标进入物体, 共同父物体下一级]物体链发送PointerEnter消息。
      3.2.4 分析ProcessDrag():若鼠标正在移动,没锁定,有拖拽物体时,检查到没有正在拖拽且允许拖拽时,向拖拽物体发送BeginDrag消息。若在拖拽中,且鼠标按下时的物体和拖拽物体不相同时,进行向鼠标按下时的物体发送PointerUp消息(强行释放);若在拖拽中,向拖拽物体发送Drag消息。
    继续3.2对ProcessMouseEvent分析:

         // Process the first mouse button fully  
            ProcessMousePress(leftButtonData);   //3.2.2分析
            ProcessMove(leftButtonData.buttonData);  //3.2.3分析
            ProcessDrag(leftButtonData.buttonData);   //3.2.4分析 下同

            // 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);

   最终会检查鼠标滚轮键的数值变化,若变化大则从当前鼠标指向的物体链找到一个可处理Scroll消息的物体,然后向该物体发送Scroll消息,至此结束3.2分析。(我TM佛了自己)
  3.3 检查是否允许发送move、submit消息给正在选中的物体,若可以且没有执行OnSelectUpdate消息,则先进行发送move消息,若move消息无法被处理则发送submit消息给正在选中物体。

后期会修改为人话版本,尽可能整合冗余部分,简化文章字数,先直接提交了,能看的懂的人只有结合源码来看。
上面仅仅是说明输入模块的Process方法,以及相关的所有事情!!! 


简单来说就是处理当前帧的鼠标按下、抬起、拖拽、点击、鼠标进入、离开等消息的传递,这个输入模块是依赖EventSystem来进行操作的,所以这也就是为什么当你场景中没有EventSystem时,会响应不了这些消息事件的原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值