2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Unity 中不同方式的事件分发和监听

Unity 中不同方式的事件分发和监听

时间:2020-06-27 19:24:12

相关推荐

Unity 中不同方式的事件分发和监听

C# 中的委托与事件

委托是一种对方法的引用(类似指针),实例委托时,可以与任何具有相同签名的方法关联。

委托使用 delegate 关键字声明,在 delegate 前加上 event 后,则将委托声明为事件,实际上为委托加上更多的限制,事件只能在声明类中调用(发布),且只能使用 +=,-+ 运算符 订阅 / 取消 。

using UnityEngine;// 发布类public class DelegateScript : MonoBehaviour{// 定义委托public delegate void SampleDelegate(int i);// 声明委托public SampleDelegate sampleDelegate;// 将委托声明为事件public event SampleDelegate sampleDelegateEvent;private void Start(){// 发布委托sampleDelegate?.Invoke(1);// 发布事件,只能在本类中调用sampleDelegateEvent?.Invoke(2);}}

using UnityEngine;// 订阅类public class DelegateTest : MonoBehaviour{public DelegateScript delegateScript; // 发布类void Start(){// 实例化委托(关联方法)delegateScript.sampleDelegate = Register;// 这个动作则叫订阅事件,只能使用 +=delegateScript.sampleDelegateEvent += Register;// 委托可在其他类中调用delegateScript.sampleDelegate(3);// 而事件不能在发布类之外调用,下面这句将报错delegateScript.sampleDelegateEvent(4);}void Register(int i){Debug.Log($"delegate {i} invoked.");}}

在平常使用时,用不用 event 关键字区别不大,但在C#文档中定义事件专指使用 event 关键字的情况。

C# 内置委托 Action and Func

在 C# System 命名空间下,提供预定义的 Action, Func 可直接使用。

using System;using UnityEngine;// 发布类public class DelegateScript : MonoBehaviour{// 预定义的 Action,无返回值public event Action<int> action;// 预定义的 Func,有返回值public event Func<int, string> func;// 预定义的 EventHandlerpublic event EventHandler<MyEventArgs> eventHandler;private void Start(){action?.Invoke(1);func?.Invoke(2);eventHandler.Invoke(this, new MyEventArgs(3));}}// 自定义事件数据public class MyEventArgs : EventArgs{public int value;public MyEventArgs(int value){this.value = value;}}

using UnityEngine;// 订阅类public class DelegateTest : MonoBehaviour{public DelegateScript delegateScript; // 引用发布类void Start(){delegateScript.action += Register;delegateScript.func += FuncRegister;delegateScript.eventHandler += EventHandlerRegister;}void Register(int i){Debug.Log($"delegate {i} invoked.");}string FuncRegister(int i){string result = $"delegate {i} invoked.";Debug.Log(result);return result;}void EventHandlerRegister(object sender, MyEventArgs e){Debug.Log($"delegate {e.value} invoked.");}}

UnityAction

由 Unity 实现的预定义 delegate。和 Action, Func 类似。

UnityEvents

可通过 Editor 进行配置绑定事件,非常方便。

using UnityEngine.Events;...// 定义 UnityEventpublic UnityEvent onStateEnter;void Start(){onStateEnter?.Invoke();}

默认的 UnityEvent 只支持无参数方法,可自定义有参数的 UnityEvent

using UnityEngine.Events;[System.Serializable]public class UnityEventInt : UnityEvent<int> {}

调用 UnityEvent

...public UnityEventInt onStateEnter;void Start(){onStateEnter?.Invoke(10);}

除了通过编辑器,也可用脚本方式绑定事件。

onStateEnter.AddListener(() => Debug.Log("Execute")); // 针对无参的 UnityEvent

Unity Messaging System

这是目前新的 UI 系统使用的消息系统(如 IPointerEnterHandler IDropHandler 等),用于取代传统的 SendMessage 方式。下面演示如何自定义消息,让状态机传递消息给目标对象。

首先,通过实现 IEventSystemHandler 定义一个新的消息接口

using UnityEngine;using UnityEngine.EventSystems;// 定义消息接口,必须实现 IEventSystemHandler 接口public interface IStateEnter : IEventSystemHandler{// 目的是将状态机中的 AnimatorStateInfo 传递给目标对象void OnStateEnter(AnimatorStateInfo stateInfo);}

在状态机中发布消息

using UnityEngine.EventSystems;public class SMB: StateMachineBehaviour{public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){// 通过 ExecuteEvents.Execute 工具函数来发布消息// 第一个参数指定消息接收的对象// 参数 x 映射前面泛型消息接口(<IStateEnter>),其他参数不重要ExecuteEvents.Execute<IStateEnter>(animator.gameObject, null, (x, y) => x.OnStateEnter(stateInfo));}}

接收消息,只有在目标对象上实现了 IStateEnter 接口,才能接收消息

using UnityEngine;public class Player : MonoBehaviour, IStateEnter{public void OnStateEnter(AnimatorStateInfo stateInfo){Debug.Log(stateInfo.xxx);}}

使用 Messaging System 需要事先指定接收的对象,就如 UI EventSystem 通过 Raycast 找到对象后,再将 IDropHandler 的消息送到该对象。

————————————————

原文链接:/kenight/article/details/98876335

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。