Unity3d Ugui 24 EventSystem事件机制

2023-11-05 02:10

本文主要是介绍Unity3d Ugui 24 EventSystem事件机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一:使用

1:实现IEventSystemHandler接口

2:添加组件EventTrigger

3:使用Ugui封装好的组件

4:3D物体相应事件

二:源码分析

1:源码地址

2:关键脚本介绍

3:执行流程

三:按照特殊需求定义自己的事件

1:制作一个2D和3D物体可以同时生效的事件。

2:响应本身的事件并且可以穿透响应下面物体的事件。


​​​​​​​

一:使用

下面几种方式都可以添加一个事件,根据实际情况选择就行,如果需要点击的详细参数,可以选择带有BaseEventData参数的方式。

1:实现IEventSystemHandler接口

ugui提供了很多接口可以直接实现对应的接口来处理对应的事件

Pointer鼠标事件:

IPointerEnterHandler- OnPointerEnter - 当光标进入对象时调用
IPointerExitHandler - OnPointerExit - 当光标退出对象时调用
IPointerDownHandler - OnPointerDown - 按下时调用
IPointerUpHandler - OnPointerUp - 抬起时调用
IPointerClickHandler - OnPointerClick - 点击时调用

Drag拖拽事件:
IInitializePotentialDragHandler - OnInitializePotentialDrag - 在找到拖动目标时调用,可用于初始化值
IBeginDragHandler - OnBeginDrag - 拖动即将开始时在拖动对象上调用
IDragHandler - OnDrag - 发生拖动时在拖动对象上调用
IEndDragHandler - OnEndDrag - 拖动完成时在拖动对象上调用
IDropHandler - OnDrop - 在拖动完成的对象上调用,在拖拉开始的地方必须先实现IDragHandler。

在实现IBeginDragHandler、IEndDragHandler、IDropHandler 这几个接口的时候,必须先实现IDragHandler接口,不然不会响应。

滚轮滚动事件:

IScrollHandler - OnScroll - 当鼠标滚轮滚动时调用

选择事件:
IUpdateSelectedHandler - OnUpdateSelected - 选中的物体每帧触发
ISelectHandler - OnSelect -选择时调用
IDeselectHandler - OnDeselect -取消选择时调用

InputManager关联组事件(同选择组要求):
IMoveHandler - OnMove - 发生移动事件(向左、向右、向上、向下)时调用
ISubmitHandler - OnSubmit - 按下提交按钮时调用
ICancelHandler - OnCancel - 按下取消按钮时调用

下面使用点击事件来演示如何使用,其他事件一样

新建一个脚本,实现IPointerClickHandler接口然后把脚本挂在UI物体上,在点击物体时就会触发。

using UnityEngine;
using UnityEngine.EventSystems;public class ClickTest : MonoBehaviour, IPointerClickHandler
{public void OnPointerClick(PointerEventData eventData){Debug.Log("IPointerClickHandler点击了" + this.name);}
}

2:添加组件EventTrigger

a:在物体上添加EventTrigger组件,点击AddNewEventType,然后选择需要的事件类型,然后点击加号,把带有自己写的脚本的物体拖入Object,选择自己定义的函数,然后点击时就会触发。

b:可以通过代码动态绑定事件

using UnityEngine;
using UnityEngine.EventSystems;
using static UnityEngine.EventSystems.EventTrigger;public class ClickTest : MonoBehaviour
{void Start(){var tri = transform.GetComponent<EventTrigger>();if (!tri){tri= transform.gameObject.AddComponent<EventTrigger>();}TriggerEvent triEvent = new TriggerEvent();triEvent.AddListener(CustomEventTriggerAddClick);tri.triggers.Add(new EventTrigger.Entry() { eventID = EventTriggerType.PointerClick, callback = triEvent });}/// <summary>/// 代码通过EventTrigger添加事件/// </summary>/// <param name="eventData"></param>public void CustomEventTriggerAddClick(BaseEventData eventData){Debug.Log("代码通过EventTrigger添加事件点击了" + this.name);}
}

3:使用Ugui封装好的组件

a:ugui有一些组件自带了事件,例如常用的Button就有Click事件,添加一个Button,在Click点击加号添加,把带有自己写的脚本的物体拖入Object,选择自己定义的函数,然后点击时就会触发。

b:通过代码动态添加

using UnityEngine;
using UnityEngine.UI;public class ClickTest : MonoBehaviour
{void Start(){var btn = transform.GetComponent<Button>();btn.onClick.AddListener(BtnCustomClick);}public void BtnCustomClick(){Debug.Log("代码绑定Button绑定" + this.name);}
}

4:3D物体相应事件

上面是在UI物体上添加事件,3D物体可以使用吗,如果事件按照上面的流程是没有任何效果的,需要给MainCamera添加PhysicsRaycaster组件,3d物体上必须有collider。然后再按照上面的流程就可以触发对应的事件了。

二:源码分析

1:源码地址

ugui的源码已经公开,需要看源码的可以自行下载,地址:https://github.com/Unity-Technologies/uGUI

当我们在场景中创建任一UI对象后,系统都会自动创建对象EventSystem,并且该对象下有两个组件:EventSystem、StandaloneInputModule。如果是旧版的Unity还有TouchInputModule组件,两个InputModule组件都继承自BaseInputModule。

2:关键脚本介绍

Event System:事件管理器,主要负责处理输入、射线投射以及发送事件,一个场景中只能有一个EventSystem组件。获取当前最新可用的InputModule模块,每个Update通过接口UpdateModules接口调用这些基本输入模块的UpdateModule接口,然后BaseInputModule会在UpdateModule接口中将自己的状态修改成'Updated',之后BaseInputModule的Process接口才会被调用。

Standalone Inout Module:标准接收器

Touch Input Module:触屏接收器

Event Trigger:事件触发器

Graphic Raycaster:界面组件的射线检测(Canvas)

Physics/Physics2D Raycaster:场景物体的射线检测。

BaseInputModule:负责发送输入事件(点击、拖拽、选中等)到具体对象,OnEnable和OnDisable方法中,会更新EventSystem的InputModule。

BaseRaycaster:射线投射

  1. GraphicRaycaster:必须挂在Canvas上,它重写了三个属性sortOrderPriority、renderOrderPriority(获取Canvas的sortingOrder和renderOrder,这在EventSystem里会作为排序依据)和eventCamera(获取canvas.worldCamera,为null则返回Camera.main),使用EventSystem.current.RaycastAll获取被照射到的对象。
  2. PhysicsRaycaster:必须挂在相机上,检查带碰撞的3d物体。使用Physics.RaycastAll来获取所有被照射到的对象。根据距离进行排序,然后包装成RaycastResult结构,加入到resultAppendList里面。EventSystem会将所有的Raycast的照射结果合在一起并排序,然后输入模块取到第一个结果的对象(距离最短)作为受输入事件影响的对象。
  3. Physics2DRaycaster:必须挂在相机上,检查带碰撞的2d物体。使用Physics2D.RaycastAll来照射对象,并且根据SpriteRenderer组件设置结果变量作为排序依据。

RaycasterManager:是一个静态类,维护了一个BaseRaycaster类型的List,BaseRaycaster的OnEnabled与OnDisabled里将自己注册到RaycasterManager。EventSystem里也通过这个类来管理所有的射线照射器。

EventData:存储事件信息

  • BaseEventData:基础的事件信息
  • PointerEventData: 存储 触摸/点击/鼠标操作 事件信息
  • AxisEventData:移动相关的事件信息,注:拖动的操作属于PointerEventData

3:执行流程

一个完整的事件流程:通过EventSystem管理,BaseInputModule输入,BaseRaycaster确定目标对象,目标对象负责接收事件并处理。

 

 

三:按照特殊需求定义自己的事件

1:制作一个2D和3D物体可以同时生效的事件。

在MainCamera上添加PhysicsRaycaster组件就可以。

2:响应本身的事件并且可以穿透响应下面物体的事件。

例如下面的效果,添加3张图片,一个立方体,点击输出点击物体的名称。所有物体都会输出Log。可以详细的控制那个物体可以穿透,那个物体不可以穿透

先自定义一个可以穿透的事件组件

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class AcrossClick : MonoBehaviour, IPointerClickHandler
{/// <summary>/// 是否可以穿透/// </summary>[SerializeField]bool canBreakThrough;/// <summary>/// 需要执行的事件/// </summary>public UnityEvent<GameObject, PointerEventData> click;public void OnPointerClick(PointerEventData eventData){click?.Invoke(this.gameObject, eventData);if (canBreakThrough){PassEvent(eventData, ExecuteEvents.pointerClickHandler);}}public void PassEvent<T>(PointerEventData eventData, ExecuteEvents.EventFunction<T> fun) where T : IEventSystemHandler{List<RaycastResult> rayResList = new List<RaycastResult>();EventSystem.current.RaycastAll(eventData, rayResList);var index = rayResList.FindIndex(r => r.gameObject == this.gameObject);//没有找到或者是点击到的最后一个物体,就不需要穿透if (index < 0 || index >= rayResList.Count - 1)return;//把事件传递给下一个物体ExecuteEvents.Execute(rayResList[index + 1].gameObject, eventData, fun);}
}

然后下一个点击以后执行的函数的脚本

using UnityEngine;
using UnityEngine.EventSystems;public class ClickTest : MonoBehaviour
{public void BtnClick(GameObject obj, PointerEventData e){Debug.Log("执行了" + obj.name);}
}

然后把ClickTest挂到一个任意物体上,把AcrossClick脚本挂在上面的3张图片一个一个立方体上。并且把canBreakThrough勾选上。把ClickTest里面的BtnClick

这篇关于Unity3d Ugui 24 EventSystem事件机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/346716

相关文章

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

Java如何通过反射机制获取数据类对象的属性及方法

《Java如何通过反射机制获取数据类对象的属性及方法》文章介绍了如何使用Java反射机制获取类对象的所有属性及其对应的get、set方法,以及如何通过反射机制实现类对象的实例化,感兴趣的朋友跟随小编一... 目录一、通过反射机制获取类对象的所有属性以及相应的get、set方法1.遍历类对象的所有属性2.获取

MySQL中的锁和MVCC机制解读

《MySQL中的锁和MVCC机制解读》MySQL事务、锁和MVCC机制是确保数据库操作原子性、一致性和隔离性的关键,事务必须遵循ACID原则,锁的类型包括表级锁、行级锁和意向锁,MVCC通过非锁定读和... 目录mysql的锁和MVCC机制事务的概念与ACID特性锁的类型及其工作机制锁的粒度与性能影响多版本

Spring使用@Retryable实现自动重试机制

《Spring使用@Retryable实现自动重试机制》在微服务架构中,服务之间的调用可能会因为一些暂时性的错误而失败,例如网络波动、数据库连接超时或第三方服务不可用等,在本文中,我们将介绍如何在Sp... 目录引言1. 什么是 @Retryable?2. 如何在 Spring 中使用 @Retryable

Python中的异步:async 和 await以及操作中的事件循环、回调和异常

《Python中的异步:async和await以及操作中的事件循环、回调和异常》在现代编程中,异步操作在处理I/O密集型任务时,可以显著提高程序的性能和响应速度,Python提供了asyn... 目录引言什么是异步操作?python 中的异步编程基础async 和 await 关键字asyncio 模块理论

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL